Skip to content
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

Action, target finder, target collector and exporter wishlist #95

Open
oantolin opened this issue Jan 8, 2021 · 193 comments
Open

Action, target finder, target collector and exporter wishlist #95

oantolin opened this issue Jan 8, 2021 · 193 comments

Comments

@oantolin
Copy link
Owner

oantolin commented Jan 8, 2021

I think I might be missing many opportunities for target finders, target collectors and exporters. Let's list some here in this issue:

Target finders

  • in eww buffers, the link at point could be targeted as a url.

Target collectors

  • in eww buffers, all the links could be collected as urls. Or a new type weblink could be introduced which has both a url and a title.

Enhancements to existing collectors:

  • the collect collector, when the region is active could collect only the candidates in the region
  • the dired collector could collect only the marked files
  • similarly, the ibuffer collector could collect only the marked buffers

Exporters

  • bookmark should export to bookmark-bmenu-mode. Done.
  • line should export to occur-mode. line was renamed consult-location and it does export to occur mode now!
  • url or weblink if introduced could export to eww-bookmark-mode, which seems like a reasonable mode for a list of links even if they are not actually bookmarks. (I'm not sure about this.)

Actions

  • url could use a download action (I'm thinking I'd only use this outside of eww buffers).
  • kill-ring could use a "remove from kill-ring" action.
@oantolin
Copy link
Owner Author

oantolin commented Jan 8, 2021

We should also think about exporters run from non-mini buffers. One that has been suggested is that in an eww buffer, export could make a list of all the links. I'm not so sure about that, probably a consult-link command is better and you can always run embark export from inside that hypothetical consult-link.

But I'm sure there are some good opportunities for export from regular buffers I'm missing. Currently the only ones are kind of boring: dired buffers export their files, ibuffers export their buffers, *Completions* buffers export their completions. Of course, dired and ibuffer are full-featured and you can also act on completions in a *Completions* buffer, so all of these exports are kind of pointless ---although I guess you do gain grid and zebra views in all cases, and the direct action minor mode might be useful for *Completions*.

@minad
Copy link
Contributor

minad commented Jan 8, 2021

Is there also a target finder wishlist? Or is the list already exhautive?

@oantolin
Copy link
Owner Author

oantolin commented Jan 8, 2021

The target finder list is not exhaustive at all! Should I make a separate issue for that or just broaden this one?

@minad
Copy link
Contributor

minad commented Jan 8, 2021

I would use one wishlist as I have in consult. I think this works quite well as some kind of general discussion thread before the details are then discussed in a separate dedicated issue.

@oantolin
Copy link
Owner Author

oantolin commented Jan 8, 2021

Earlier when I mentioned eww links I was really talking about just collecting them and forgot to say what kind of buffer they should export to: maybe an eww-bookmark-mode buffer is reasonable, even though they aren't bookmarks.

@oantolin oantolin changed the title Exporter wishlist Target finder, target collector and exporter wishlist Jan 8, 2021
@oantolin oantolin changed the title Target finder, target collector and exporter wishlist Action, target finder, target collector and exporter wishlist Jan 8, 2021
@oantolin oantolin pinned this issue Jan 8, 2021
@oantolin
Copy link
Owner Author

oantolin commented Jan 8, 2021

OK, I've broadened this issue on your advice @minad. (I don't want the wishlist to also cover new commands, since in fact, I'm pretty skeptical about adding any new top-level commands to Embark at this point, except possibly the resume functionality, if we think it fits better in Embark.)

@oantolin
Copy link
Owner Author

oantolin commented Jan 8, 2021

Oh, I just remembered some actions for variables I often miss: set-variable and customize-set-variable, maybe even customize-variable.

@oantolin
Copy link
Owner Author

oantolin commented Jan 9, 2021

Good news: now consult-line, consult-outline, consult-mark and consult-global-mark export to occur mode buffers and e (for occur-edit-mode) works in them!

@minad
Copy link
Contributor

minad commented Jan 9, 2021

@oantolin This is amazing! I already have it mentioned here: https://github.com/minad/consult#integration-with-embark. Now I can remove the work in progress note 🥳

@oantolin
Copy link
Owner Author

Oh, I just remembered some actions for variables I often miss: set-variable and customize-set-variable, maybe even customize-variable.

I added these for variables, and for commands I added execute-extended-command, global-set-key and local-set-key. 846cfbd

@protesilaos
Copy link

I am just sharing this good idea for targeting video links: https://jao.io/blog/2021-01-09-embarking-videos.html. Natural complements are audio files and an action to yt-dl the target (audio could call mpv with the --no-video flag).

Maybe this is something that can be of use.

@sheijk
Copy link

sheijk commented Jan 11, 2021

@oantolin the actions for variables and commands are not available here. I checked that the commit you referenced is applied, value of embark-keymap-alist set accordingly, etc. But when I act on something like (defcustom e|mbark-keymap-alist (point at "|" char) I don't see customize or set variable options, same with commands like embark-act (version 20210111.1408). Can I see which map has been selected somewhere?

[edit: (embark--target) returns (symbol . "name") when invoked from source code. It works in C-h v etc. So an extended classifier for elisp variables/commands would be great]

@sheijk
Copy link

sheijk commented Jan 11, 2021

org-mode classifiers and actions would also be great. Or would this be better for an external package?

@oantolin
Copy link
Owner Author

@sheijk The variable and command specific actions are currently only available from minibuffer commands for those categories. For example you get the command actions for candidates in M-x in recent Emacsen. If you use Marginalia, then you get the command actions in M-x even on older Emacsen. And again, with Marginalia, you get the variable actions from describe-variable, for example, or from customize-variable.

The point is that, as you found, they are not supposed to work on symbols in regular buffers... yet! I've been thinking about refining the type. It would be much better once the multiple-targets stuff is finished #92, but for now I guess I could just pick an order: prefer command over variable if the symbol is both things. If Emacs were extended in Guile we wouldn't have these problems... 😛

@oantolin
Copy link
Owner Author

org-mode classifiers and actions would also be great. Or would this be better for an external package?

Possibly a separate package would be better, I'm not sure. I mean Org does come with Emacs. But that can be decided later, the first thing is to decide what kinds of targets and actions would be useful in Org buffers. Did you have any thing in mind? For a target type to be really useful ideally it should have several associated actions.

@sheijk
Copy link

sheijk commented Jan 11, 2021

Separate package makes sense, or at least a separate elisp file to not require loading org-mode when embark gets used in other buffers. I've recently made a little transient based menu for org, I think most actions offered there would be good embark candidates. Some examples for actions would be:

  • TODO items - toggle next state, set explicit state, remove state
  • Headline - same as TODO, org-update-checkbox-count, move up/down, (de)indent, cut tree
  • Timestap - change date, toggle type, show in calendar
  • Link - open, edit
  • Region - toggle bold/italic/..
  • List items - set to "[ ]", "[x]", "[-]", no checkbox, indent/outdent, org-list-repair, org-list-make-subtree, cycle-style, maybe move up/down
  • Table: evaluate (cell/line/all/all-until-nothing-changes), add/delete/move row/column, edit field, blank field, org-copy-down, set field/column formula

@oantolin
Copy link
Owner Author

I think your suggested org targets and actions are very good and that a separate embark-org (or org-embark?, how does that work?) package with them would be reasonable, but, wow, your org-menu package looks fantastic, @sheijk! I'd say your package takes the pressure off Embark to provide similar functionality with a different interface. 😄

@minad
Copy link
Contributor

minad commented Jan 11, 2021

You could create an embark-org.el file similar to consult-flymake.el in order to retain lazy loading but distribute it as part of embark melpa.

@sheijk
Copy link

sheijk commented Jan 11, 2021

@oantolin or maybe start it with the actions I already made. Are you looking for contributions (no promise!)?

@oantolin
Copy link
Owner Author

@sheijk I added a transformer to refine symbol to command or variable if possible, for when you act on the symbol at point in a regular buffer. 296ad80

@oantolin
Copy link
Owner Author

I am just sharing this good idea for targeting video links: https://jao.io/blog/2021-01-09-embarking-videos.html. Natural complements are audio files and an action to yt-dl the target (audio could call mpv with the --no-video flag).

Thanks for pointing this out, @protesilaos. I wrote to jao to suggest a slightly different implementation which he wrote about, and I noticed he also wrote an async Spotify client using Consult and Marginalia!

@protesilaos
Copy link

oantolin: I wrote to jao to suggest a slightly different implementation which he wrote about, and I noticed he also wrote an async Spotify client using Consult and Marginalia!

Yes, I have read them. My plan is to copy and adapt the video targeting part (never used spotify). More generally, I am excited to see what kind of solutions, tips and tricks the community comes up with for those packages.

@minad
Copy link
Contributor

minad commented Jan 12, 2021

@oantolin @protesilaos Regarding the spotify client, it is exciting that they implemented a web access using the async api! I have some small experiments in the consult websearch branches as well, but they turned out to be not useful.

@astoff
Copy link
Contributor

astoff commented Jan 12, 2021

I think the way Embark works on a regular buffer is too Elisp-centric. Hopefully most people spend most of their time in Emacs doing other things!

For the purposes of embark-target-symbol-at-point, I would argue that symbol should mean a symbol in the current major mode. So the d action would be bound to xref-find-definitions. It's less clear what to bind to h, since there's no “describe thing at point” in xref (or whatever Emacs component this would fit into). Anyway, I suggest binding the h key to display-local-help. This is mostly useless in itself, but at least the user can remap that command to suitable major-mode specific values (describe-symbol in Elisp, cider-doc in Cider, etc.). Plus, it would work out-of-the-box with Eglot, which does precisely that remapping in its own mode-map.

On the other hand, I'm fine with the eval-region binding in embark-region-map because there's no better option, and, as above, one can use remaps to improvise a generic interface to the “send to repl” action across major modes.

There could still be an embark-target-emacs-lisp-symbol-at-point, but it should probably check if the buffer is in Elisp mode. Then it wouldn't work in random places like help buffers, but at least Embark would not capriciously (not) recognize words in regular text or other programming languages just because they happen to (not) have a meaning in Elisp.

@minad
Copy link
Contributor

minad commented Jan 12, 2021

@astoff I agree! But I guess thing-at-point is also elisp centric. Unfortunately elisp is somehow more first class in Emacs then the other major modes. But that is natural since you can see it as a whole programmable environment.

@astoff
Copy link
Contributor

astoff commented Jan 12, 2021

@minad thing-at-point uses the syntax table to decide what is a symbol. (So in most prog-modes, but not in lisp-mode, (thing-at-point 'symbol) just after the text x-y returns y.)

@Zetagon
Copy link

Zetagon commented Jun 14, 2021

@oantolin Any comment on this from earlier in this thread? #95 (comment)

@minad
Copy link
Contributor

minad commented Jun 14, 2021

@Zetagon Related to the current discussion - the aforementioned cmap package implements a set of useful org actions at point and a set of org target finders. You may want to take a look what exists there.

@oantolin
Copy link
Owner Author

I'm sorry @Zetagon, I haven't really had a chance to think about this.

I do like the idea of having a target finder for org elements, but I think deciding what that target finder should return is a little tricky and requires contemplating what actions one would want. The two natural choices for it are to return the org element as a string, and to return a non-string (like the region target finder which just returns the symbol <region> if there is an active region). The point is that if the target finder returns a string, that string will be injected at the first minibuffer prompt that the action produces; but if the target is not a string, nothing is injected.

So you need to look at the likely actions and see how they actually work. In the org case most probably don't take the org-element as a string, but rather act on the thing at point. I also find it hard to decide whether the layered approach you took, with extra configuration variables for elements types and link types is really necessary. I haven't forgotten this, but haven't had time to think about it yet.

@Zetagon
Copy link

Zetagon commented Jun 14, 2021

@oantolin

I'm sorry @Zetagon, I haven't really had a chance to think about this.

Yeah that is completely understandable. I just didn't want it to drown in the discussion afterwards 🙂 Do take your time, I will just find something else to play with!

I do like the idea of having a target finder for org elements, but I think deciding what that target finder should return is a little tricky and requires contemplating what actions one would want.

In my current implementation each element has its own target finder so what we return can depend on the target. For example the link target returns the link string, but that doesn't stop target finders for other elements to return, say a symbol or the parsed AST. Is there an advantage having the same return type for all elements I'm missing?

I also find it hard to decide whether the layered approach you took, with extra configuration variables for elements types and link types is really necessary. I haven't forgotten this, but haven't had time to think about it yet.

I think there is a greater benefit to having configuration variables for links than for element types at least, because users can add their own link types.

@astoff
Copy link
Contributor

astoff commented Jun 14, 2021

(sexp)
^    ^^

In my opinion the second of those positions should target the symbol sexp inside the sexp.

sexp targets should work at points that the sexp navigation commands leave you (C-M-f C-M-b C-M-u C-M-d C-M-n C-M-p).

An alternative would be to follow show-paren-mode's example.

@oantolin
Copy link
Owner Author

Oh, right! I fully agree with @astoff: show-paren-mode has it right: target the sexp only right before an opening parenthesis or right after a closing parenthesis. And as @astoff also said, right before the closing parenthesis the target should be the symbol to the left, which is what currently happens.

@oantolin
Copy link
Owner Author

@Zetagon

Yeah that is completely understandable. I just didn't want it to drown in the discussion afterwards 🙂 Do take your time, I will just find something else to play with!

Thanks for being understanding. We should probably create a separate issue for this, since as you say it could get drowned out here.

In my current implementation each element has its own target finder so what we return can depend on the target. For example the link target returns the link string, but that doesn't stop target finders for other elements to return, say a symbol or the parsed AST. Is there an advantage having the same return type for all elements I'm missing?

Oh, no, there's no advantage in all of them returning the same type, and that is not what I meant. I meant we should consider for each type what to return.

I think there is a greater benefit to having configuration variables for links than for element types at least, because users can add their own link types.

Yes, I agree.

@hmelman
Copy link

hmelman commented Jun 14, 2021

Oh, right! I fully agree with @astoff: show-paren-mode has it right: target the sexp only right before an opening parenthesis or right after a closing parenthesis. And as @astoff also said, right before the closing parenthesis the target should be the symbol to the left, which is what currently happens.

Agreed. Is this only for lisp modes or should this work in other programming modes that define sexps in some way (I think most do as expressions)? The mark, kill and indent actions would apply. Maybe not eval or expand though a send to interpreter might.

@minad
Copy link
Contributor

minad commented Jun 14, 2021

Such a sexp target finder is quite simple, even simpler than the one I proposed before:

(defun embark-target-sexp-at-point ()
  "Target sexp at point."
  (when (and (or (eq (char-after) ?\()
                 (eq (char-before) ?\)))
             (thing-at-point 'sexp))
    '(sexp <sexp>)))

@oantolin
Copy link
Owner Author

oantolin commented Jun 14, 2021

@hmelman It would be nice if it worked in other programming modes as well, but in my experience the definition of sexp often isn't good enough. Try mark-sexp in different places and you'll see what I mean. It does mark a block in braces, but that's about the only thing it does right. In C, for example, given if (a==b) { printf("Oh no!\n"); } it thinks if is an expression...

@oantolin
Copy link
Owner Author

Given the state of sexps in other modes, I think a minor tweak of @minad's target finder to use syntax class ( instead of the literal character ( is probably as good as it gets without excessive work.

Oh, maybe syntax class ( and " should be considered.

@minad
Copy link
Contributor

minad commented Jun 14, 2021

@oantolin I am not sure about " since this may once again clash with other finders. file names? If we use only the parentheses we are at least safe that nothing bad happens. I also didn't consider other programming languages - I think these things just don't generalize well over other languages.

@minad
Copy link
Contributor

minad commented Jun 14, 2021

But generally one could add additional target finders which are programming language specific. Or maybe it is even possible to do a bit better with tree sitter. However I think such actions should be maintained in third party packages.

@oantolin
Copy link
Owner Author

I think file names in strings should be safe. Given "~/a/path/" ffap only recognizes the file if you are inside the string, this leaves the positions just outside the string on either side available for treating the string as an s-expression.

@hmelman
Copy link

hmelman commented Jan 20, 2022

I have the following in a markdown-mode buffer.

- [Maracaibo: The Uprising](https://boardgamegeek.com/boardgameexpansion/338013/maracaibo-uprising)

I wanted to use the link text, "Maracaibo: The Uprising", in an external app (a browser search). I positioned point inside the word "Maracaibo" and could invoke expand-region twice and use M-w to copy the desired text but I wanted to use embark.

I didn't think it would work but invoking embark-act twice highlighted the desired text as an expression, almost. It included the open and close brackets because that's how sexps work in text mode.

I'd love if embark could act on this text as a target in markdown-mode. I suspect it would be useful in some other modes like org or html. I'm not sure if expression is the right target to use. expand-region works by selecting first er/mark-inside-pairs and then er/mark-outside-pairs. I could see that being useful in prog-modes too, at least in comments (it also has functions for inside/outside quotes).

Previously in this issue we talked about targets for links, but this is different as I don't want the url or the whole link, I think I want the text marked by a delimiter surrounding point which seems generally useful, but maybe someone has other ideas.

@minad
Copy link
Contributor

minad commented Feb 13, 2022

What about new targets button and widget? We can use button-at and widget-at to find them. There are not many actions, but Emacs 28 introduced button-describe and widget-describe.

@oantolin
Copy link
Owner Author

oantolin commented Feb 23, 2022

To act inside the delimiters of an s-expression, @hmelman, you could use this (which takes advantage of shiny new infrastructure I just added in f741dab):

(defun embark-mark-inside ()
  "Mark inside an s-expression, excluding the delimiters."
  (interactive)
  (forward-char)
  (push-mark)
  (up-list)
  (backward-char)
  (activate-mark))

(add-to-list 'embark-repeat-actions '(embark-mark-inside . region))

(add-to-list 'embark-pre-action-hooks
             '(embark-mark-inside embark--beginning-of-target))

(define-key embark-expression-map "I" #'embark-mark-inside)

The new thing added in that commit was the ability to add pairs of the form (action . next-target-type) to embark-repeat-actions. Previously, at which point of the target cycle you started the next action, was hard-coded.

I'm not sure whether to add that to Embark (and wouldn't mind hearing some opinions), but if not, it can certainly go on the wiki.

@minad
Copy link
Contributor

minad commented Feb 23, 2022

Looks a bit special to me, but we also have hash function actions so why not? I am not sure where to draw the line. ;)

@oantolin
Copy link
Owner Author

Oh, I should probably check the first and last character really are delimiters, because that's not always true of sexps in non-lisp prog modes. 🙄

@minad
Copy link
Contributor

minad commented Feb 23, 2022

Oh, I should probably check the first and last character really are delimiters, because that's not always true of sexps in non-lisp prog modes.

Hmm, maybe this is a line I would draw. If an action gets too complicated it should not be added, since then there is no clear line on where to stop. Of course exceptions can be made for complex actions, which are considered important.

While the hash actions are obscure they are only trivial wrappers. Additional wrapper actions for builtin functionality, which cannot be used otherwise in Embark, are nice to have.

@pcrama
Copy link

pcrama commented Apr 6, 2022

It would be great if EMBARK was made aware of bug-reference-mode and picked the URL as a target out of the box.

I have code in my init.el to do that by looking at the overlay category (bug-reference) and (overlay-get o 'bug-reference-url) of the (overlays-at (point)) but since I did not sign the FSF papers, I do not dare paste my code here.

@minad
Copy link
Contributor

minad commented Apr 6, 2022

@pcrama Embark already does. See

embark/embark.el

Lines 766 to 771 in 592287b

(defun embark-target-bug-reference-at-point ()
"Target a bug reference at point."
(when-let ((ov (seq-find (lambda (ov) (overlay-get ov 'bug-reference-url))
(overlays-at (point)))))
`(url ,(overlay-get ov 'bug-reference-url)
,(overlay-start ov) . ,(overlay-end ov))))
.

@pcrama
Copy link

pcrama commented May 3, 2022

Thanks and sorry for missing it. I still don't know how I initially got the impression it wasn't working but now it works for me.

I don't know how to close this, unfortunately but from my point of view, this issue is resolved.

@oantolin
Copy link
Owner Author

oantolin commented May 5, 2022

I've started an embark-org package in this repo, which is one of things discussed long ago in this issue. I open a separate issue for discussion of what to add to embark-org, #502

@jumper047
Copy link

BTW what is the preferable way to contribute my own finders/collectors? Recently I tinkered with embark and emacs-slack packages and added some actions on slack messages. Seems like it can be useful for someone, and I have the choice - to contribute it to the main embark repo or to go with separate package on my own.
(sorry if it's wrong topic for such questions)

@oantolin
Copy link
Owner Author

That's great @jumper047! Slack is out of scope for Embark, which only comes with key bindings and special actions for stuff that is built-in to Emacs. Integration with Slack would fit well in the Embark wiki, if it is small and simple, or your own package if it is more substantial.

@minad
Copy link
Contributor

minad commented Apr 17, 2023

This is rather an issue for an inverse wishlist, this is more of a curation aspect - I think elint-defun should be removed from the defun map. This command is obsolete and weak in contrast to the linting performed by package-lint or the bytecode compiler. The bytecode compiler is continuously extended with new warnings and improved in Emacs master, which cannot be said about the elint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests