emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Problem with let/cl-letf binding stuff with org-capture
@ 2023-02-10 15:05 Arthur Miller
  2023-02-10 15:38 ` Ruijie Yu via General discussions about Org-mode.
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Arthur Miller @ 2023-02-10 15:05 UTC (permalink / raw)
  To: emacs-orgmode


Based on a Reddit thread:

https://www.reddit.com/r/emacs/comments/10xhvd8/a_little_readstring_utility_using_an_org_mode/j7xziao/?context=3

I did a small experiment to see if I can re-use org-capture, to just capture a
string from a buffer, without actually writing to any file.

My plan was to just let-bind org-capture-finalize with cl-letf:

#+begin_src emacs-lisp
(defun my-read-string ()
  (cl-letf (((symbol-function 'org-capture-finalize) ;; C-c C-c
             (lambda (&optional _) (interactive "P") (buffer-string)))
            ((symbol-function 'org-kill-note-or-show-branches) #'kill-buffer)) ;; C-c C-k
    (let ((org-capture-templates '(("s" "string" plain (function ignore)))))
      (org-capture nil "s"))))
#+end_src

Unfortunately, that does not work. Regardless of binding, and if I used cl-letf
or cl-flet or cl-labels, or old let, or something brewed on the internet, the
binding org-capture see for org-capture-finalize, is the original one from
org-capture.el.

My second experiment was to abstract the finalize function into a funcallable
fariable in org-capture.el (I have patched org-capture.el with this):

#+begin_src emacs-lisp
(defvar org-capture-finalizer #'org-capture--default-finalize)

(defun org-capture-finalize (&optional stay-with-capture)
  "Finalize the capture process.
With prefix argument STAY-WITH-CAPTURE, jump to the location of the
captured item after finalizing."
  (interactive "P")
  (funcall org-capture-finalizer stay-with-capture))


(defun org-capture--default-finalize (&optional stay-with-capture)
  "Default implementation for org-capture finalizer function."

;; this is the original org-capture-finalize just renamed to "default-finalize"
)
#+end_src

So I could then have something like this (never mind C-c C-k function being
removed):

#+begin_src emacs-lisp
(defun my-read-string ()
  (let ((org-capture-templates '(("s" "string" plain (function ignore))))
        (org-capture-finalizer
         (lambda (&optional _) (interactive "P") (buffer-string))))
    (org-capture nil "s")))
#+end_src

However I see that the binding for the org-capture-finalizer, in capture buffer,
is still the default 'org-capture--default-finalize' and not my lambda.

I am really not an expert on emacs lisp; and I do understand that this is
somewhat "creative" use of org-capture (to put it nicely :-)), but I would like
to understand what is going on here.

I don't understand why let-binding here does not work? If I take (symbol-functon
'org-capture) I see it is a closure. I am not sure if it has something with the
problem to do? I have tested to disable lexical binding, re-eval things, but
the let-binding seems rock stable :). Nothing makes org-capture to reconsider
using my local let-binding.

I would really like to understand this, so please if someone can explain it, I
will appreciate to hear.

Thanks in advance
/arthur


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-10 15:05 Problem with let/cl-letf binding stuff with org-capture Arthur Miller
@ 2023-02-10 15:38 ` Ruijie Yu via General discussions about Org-mode.
  2023-02-10 16:29   ` Arthur Miller
  2023-02-10 19:00 ` Bruno Barbier
  2023-02-11 16:49 ` Ihor Radchenko
  2 siblings, 1 reply; 19+ messages in thread
From: Ruijie Yu via General discussions about Org-mode. @ 2023-02-10 15:38 UTC (permalink / raw)
  To: Arthur Miller; +Cc: emacs-orgmode

Hi Arthur,

Please excuse my brevity and semi-random line of thought, as I’m replying on mobile right now.  See below. 

> On Feb 10, 2023, at 23:11, Arthur Miller <arthur.miller@live.com> wrote:
> 
> 
> Based on a Reddit thread:
> 
> https://www.reddit.com/r/emacs/comments/10xhvd8/a_little_readstring_utility_using_an_org_mode/j7xziao/?context=3
> 
> I did a small experiment to see if I can re-use org-capture, to just capture a
> string from a buffer, without actually writing to any file.
> 
> My plan was to just let-bind org-capture-finalize with cl-letf:
> 
> #+begin_src emacs-lisp
> (defun my-read-string ()
> (cl-letf (((symbol-function 'org-capture-finalize) ;; C-c C-c
>           (lambda (&optional _) (interactive "P") (buffer-string)))
>          ((symbol-function 'org-kill-note-or-show-branches) #'kill-buffer)) ;; C-c C-k
>  (let ((org-capture-templates '(("s" "string" plain (function ignore)))))
>    (org-capture nil "s"))))
> #+end_src

Based on my somewhat-limited experience with CL (and elisp), I have never seen this particular type of letf structure.  What I am used to seeing and writing is the following:

(cl-letf ((f (x) (1+ x))
   (1+ (f 2)))
; => 4

In particular, IIUC, I don’t think you would need symbol-function here.  Maybe you can learn more from the docstring of cl-letf than me trying to drain my memory on this topic without reference. 

Also, in the code snippet you provided, what *should* org-capture-finalize be?  A function that can be called like this:

   (org-capture-finalize arg1 arg2)

? Or a variable containing a function (reference) that can be called like this:

   (funcall org-capture-finalize arg1 arg2)

?  In the former case you might be able to use cl-letf, and in the latter case you should use let with a lambda value. 

> Unfortunately, that does not work. Regardless of binding, and if I used cl-letf
> or cl-flet or cl-labels, or old let, or something brewed on the internet, the
> binding org-capture see for org-capture-finalize, is the original one from
> org-capture.el.
> 
> My second experiment was to abstract the finalize function into a funcallable
> fariable in org-capture.el (I have patched org-capture.el with this):
> 
> #+begin_src emacs-lisp
> (defvar org-capture-finalizer #'org-capture--default-finalize)
> 
> (defun org-capture-finalize (&optional stay-with-capture)
> "Finalize the capture process.
> With prefix argument STAY-WITH-CAPTURE, jump to the location of the
> captured item after finalizing."
> (interactive "P")
> (funcall org-capture-finalizer stay-with-capture))
> 
> 
> (defun org-capture--default-finalize (&optional stay-with-capture)
> "Default implementation for org-capture finalizer function."
> 
> ;; this is the original org-capture-finalize just renamed to "default-finalize"
> )
> #+end_src
> 
> So I could then have something like this (never mind C-c C-k function being
> removed):
> 
> #+begin_src emacs-lisp
> (defun my-read-string ()
> (let ((org-capture-templates '(("s" "string" plain (function ignore))))
>      (org-capture-finalizer
>       (lambda (&optional _) (interactive "P") (buffer-string))))
>  (org-capture nil "s")))
> #+end_src
> 
> However I see that the binding for the org-capture-finalizer, in capture buffer,
> is still the default 'org-capture--default-finalize' and not my lambda.

I guess this answers part of my question in my previous paragraph.  Is org-capture-finalizer defined via defvar?  If so, does it help if you put an empty defvar before the let binding?  If not, maybe someone actually using Emacs right now can be of more help here. 

> I am really not an expert on emacs lisp; and I do understand that this is
> somewhat "creative" use of org-capture (to put it nicely :-)), but I would like
> to understand what is going on here.
> 
> I don't understand why let-binding here does not work? If I take (symbol-functon
> 'org-capture) I see it is a closure. I am not sure if it has something with the
> problem to do? I have tested to disable lexical binding, re-eval things, but
> the let-binding seems rock stable :). Nothing makes org-capture to reconsider
> using my local let-binding.
> 
> I would really like to understand this, so please if someone can explain it, I
> will appreciate to hear.
> 
> Thanks in advance
> /arthur

Best,


RY


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-10 15:38 ` Ruijie Yu via General discussions about Org-mode.
@ 2023-02-10 16:29   ` Arthur Miller
  0 siblings, 0 replies; 19+ messages in thread
From: Arthur Miller @ 2023-02-10 16:29 UTC (permalink / raw)
  To: Ruijie Yu; +Cc: emacs-orgmode

Ruijie Yu <ruijie@netyu.xyz> writes:

> Hi Arthur,
>
> Please excuse my brevity and semi-random line of thought, as I’m replying on mobile right now.  See below. 
>
>> On Feb 10, 2023, at 23:11, Arthur Miller <arthur.miller@live.com> wrote:
>> 
>> 
>> Based on a Reddit thread:
>> 
>> https://www.reddit.com/r/emacs/comments/10xhvd8/a_little_readstring_utility_using_an_org_mode/j7xziao/?context=3
>> 
>> I did a small experiment to see if I can re-use org-capture, to just capture a
>> string from a buffer, without actually writing to any file.
>> 
>> My plan was to just let-bind org-capture-finalize with cl-letf:
>> 
>> #+begin_src emacs-lisp
>> (defun my-read-string ()
>> (cl-letf (((symbol-function 'org-capture-finalize) ;; C-c C-c
>>           (lambda (&optional _) (interactive "P") (buffer-string)))
>>          ((symbol-function 'org-kill-note-or-show-branches) #'kill-buffer)) ;; C-c C-k
>>  (let ((org-capture-templates '(("s" "string" plain (function ignore)))))
>>    (org-capture nil "s"))))
>> #+end_src
>
> Based on my somewhat-limited experience with CL (and elisp), I have never seen
> this particular type of letf structure.  What I am used to seeing and writing is
> the following:

It uses "place" or "field" to set the symbol binding, as in setf or incf.

You can read more on SX:

https://stackoverflow.com/questions/39550578/in-emacs-what-is-the-difference-between-cl-flet-and-cl-letf

> (cl-letf ((f (x) (1+ x))
>    (1+ (f 2)))
> ; => 4
>
> In particular, IIUC, I don’t think you would need symbol-function here.  Maybe
> you can learn more from the docstring of cl-letf than me trying to drain my
> memory on this topic without reference.
>
> Also, in the code snippet you provided, what *should* org-capture-finalize be?  A function that can be called like this:
>
>    (org-capture-finalize arg1 arg2)
>
> ? Or a variable containing a function (reference) that can be called like this:
>
>    (funcall org-capture-finalize arg1 arg2)
>
> ?  In the former case you might be able to use cl-letf, and in the latter case you should use let with a lambda value. 
>
>> Unfortunately, that does not work. Regardless of binding, and if I used cl-letf
>> or cl-flet or cl-labels, or old let, or something brewed on the internet, the
>> binding org-capture see for org-capture-finalize, is the original one from
>> org-capture.el.
>> 
>> My second experiment was to abstract the finalize function into a funcallable
>> fariable in org-capture.el (I have patched org-capture.el with this):
>> 
>> #+begin_src emacs-lisp
>> (defvar org-capture-finalizer #'org-capture--default-finalize)
>> 
>> (defun org-capture-finalize (&optional stay-with-capture)
>> "Finalize the capture process.
>> With prefix argument STAY-WITH-CAPTURE, jump to the location of the
>> captured item after finalizing."
>> (interactive "P")
>> (funcall org-capture-finalizer stay-with-capture))
>> 
>> 
>> (defun org-capture--default-finalize (&optional stay-with-capture)
>> "Default implementation for org-capture finalizer function."
>> 
>> ;; this is the original org-capture-finalize just renamed to "default-finalize"
>> )
>> #+end_src
>> 
>> So I could then have something like this (never mind C-c C-k function being
>> removed):
>> 
>> #+begin_src emacs-lisp
>> (defun my-read-string ()
>> (let ((org-capture-templates '(("s" "string" plain (function ignore))))
>>      (org-capture-finalizer
>>       (lambda (&optional _) (interactive "P") (buffer-string))))
>>  (org-capture nil "s")))
>> #+end_src
>> 
>> However I see that the binding for the org-capture-finalizer, in capture buffer,
>> is still the default 'org-capture--default-finalize' and not my lambda.
>
> I guess this answers part of my question in my previous paragraph.  Is
> org-capture-finalizer defined via defvar?  If so, does it help if you put an
> empty defvar before the let binding?  If not, maybe someone actually using Emacs
> right now can be of more help here.

These were two different examples; one that let-binds the function
'org-caputre-finalize', via cl-letf and the latter one that was completely
different in which I have defvared a symbol so I can let-bind it as a variable.

>                                       If not, maybe someone actually using Emacs
> right now can be of more help here.

Don't worry; thanks for the help anyway!

/a




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-10 15:05 Problem with let/cl-letf binding stuff with org-capture Arthur Miller
  2023-02-10 15:38 ` Ruijie Yu via General discussions about Org-mode.
@ 2023-02-10 19:00 ` Bruno Barbier
  2023-02-11  6:33   ` Arthur Miller
  2023-02-11 16:49 ` Ihor Radchenko
  2 siblings, 1 reply; 19+ messages in thread
From: Bruno Barbier @ 2023-02-10 19:00 UTC (permalink / raw)
  To: Arthur Miller, emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

> However I see that the binding for the org-capture-finalizer, in capture buffer,
> is still the default 'org-capture--default-finalize' and not my lambda.
>
> I am really not an expert on emacs lisp; and I do understand that this is
> somewhat "creative" use of org-capture (to put it nicely :-)), but I would like
> to understand what is going on here.
>
> I don't understand why let-binding here does not work?

Your bindings probably work. But, as the function `org-capture'
just *starts* the capture process, they are removed when exiting the
'let', before you even begin editing your capture.

I'm not sure I understand your use case:  if you have a piece
of org text, you can put it anywhere (possibly using refiling).

If you really want to just get the piece of text, you might be able to
use the hook `org-capture-mode-hook' to replace the key binding to
'C-c C-c' in the capture buffer, so that it calls your own function that
will take the string and call `org-capture-kill'.

Note that they are safer way to modify Emacs behavior than overwriting
the functions. You can usually use hooks (like `org-capture-mode-hook'):

  (info "(elisp) Hooks")

or, if it's not possible, you can advise the functions:

  (info "(elisp) Advising Functions")


Bruno








^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-10 19:00 ` Bruno Barbier
@ 2023-02-11  6:33   ` Arthur Miller
  2023-02-11  7:58     ` Bruno Barbier
  0 siblings, 1 reply; 19+ messages in thread
From: Arthur Miller @ 2023-02-11  6:33 UTC (permalink / raw)
  To: Bruno Barbier; +Cc: emacs-orgmode

Bruno Barbier <brubar.cs@gmail.com> writes:

> Arthur Miller <arthur.miller@live.com> writes:
>
>> However I see that the binding for the org-capture-finalizer, in capture buffer,
>> is still the default 'org-capture--default-finalize' and not my lambda.
>>
>> I am really not an expert on emacs lisp; and I do understand that this is
>> somewhat "creative" use of org-capture (to put it nicely :-)), but I would like
>> to understand what is going on here.
>>
>> I don't understand why let-binding here does not work?
>
> Your bindings probably work. But, as the function `org-capture'
> just *starts* the capture process, they are removed when exiting the
> 'let', before you even begin editing your capture.

Yes of course :) I am quite aware that org-capture just setups the buffer, and
that org-capture-finalize finnishes by writing stuff to files etc, and yet I
have tottally forgott it when writing this. This for opening my eyes.

> I'm not sure I understand your use case:  if you have a piece
> of org text, you can put it anywhere (possibly using refiling).

it is just a fun test. I wouldn't do that myself normally and I have no idea why
the blog author needs it either. If I wanted to input multiline
text into some dokument I would open dokument itself. But this was just a
thought I am testing; you can read in the link I posted in the first mail.

> If you really want to just get the piece of text, you might be able to
> use the hook `org-capture-mode-hook' to replace the key binding to
> 'C-c C-c' in the capture buffer, so that it calls your own function that
> will take the string and call `org-capture-kill'.

In this case you wouldn't like to replace the key binding, it would affect all
org-capture buffers; the point is just to replace it when called in certain
context (my-read-line). Let-binding the function in this context achieves
exactly the same effect of C-c C-c beng bound to my function but without
affecting all org-capture-buffers.

>                You can usually use hooks (like `org-capture-mode-hook'):
>   (info "(elisp) Hooks")
>
> or, if it's not possible, you can advise the functions:
>
>   (info "(elisp) Advising Functions")

Yes, I am aware of both hooks and advising; but again, with those I would affect
all uses of the function, and that would lead to checking some global state or
variable to switch on, which is not optimal either. With let-binding we can have
different behaviour only in a certain context.

Anyway, thanks, I needed the reminder above.

cheers
/arthur


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-11  6:33   ` Arthur Miller
@ 2023-02-11  7:58     ` Bruno Barbier
  2023-02-11 16:14       ` Arthur Miller
  0 siblings, 1 reply; 19+ messages in thread
From: Bruno Barbier @ 2023-02-11  7:58 UTC (permalink / raw)
  To: Arthur Miller; +Cc: emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

>> Bruno Barbier <brubar.cs@gmail.com> writes:
>> If you really want to just get the piece of text, you might be able to
>> use the hook `org-capture-mode-hook' to replace the key binding to
>> 'C-c C-c' in the capture buffer, so that it calls your own function that
>> will take the string and call `org-capture-kill'.
>
> In this case you wouldn't like to replace the key binding, it would affect all
> org-capture buffers; the point is just to replace it when called in certain
> context (my-read-line). Let-binding the function in this context achieves
> exactly the same effect of C-c C-c beng bound to my function but without
> affecting all org-capture-buffers.

The hook `org-capture-mode-hook' will be run in your special
capture buffer. You can override the "C-c C-c" binding only there.

>
> Yes, I am aware of both hooks and advising; but again, with those I would affect
> all uses of the function, and that would lead to checking some global state or
> variable to switch on, which is not optimal either. With let-binding we can have
> different behaviour only in a certain context.

Even if I could let bind the function at the right time, I would avoid
that solution, as I can't garantuee that this global hack will not break
other parts of Emacs (other captures, output filters, threads, timers,
etc.).

>
> Anyway, thanks, I needed the reminder above.

You're welcome.

Bruno



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-11  7:58     ` Bruno Barbier
@ 2023-02-11 16:14       ` Arthur Miller
  2023-02-11 19:23         ` Bruno Barbier
  0 siblings, 1 reply; 19+ messages in thread
From: Arthur Miller @ 2023-02-11 16:14 UTC (permalink / raw)
  To: Bruno Barbier; +Cc: emacs-orgmode

Bruno Barbier <brubar.cs@gmail.com> writes:

> Arthur Miller <arthur.miller@live.com> writes:
>
>>> Bruno Barbier <brubar.cs@gmail.com> writes:
>>> If you really want to just get the piece of text, you might be able to
>>> use the hook `org-capture-mode-hook' to replace the key binding to
>>> 'C-c C-c' in the capture buffer, so that it calls your own function that
>>> will take the string and call `org-capture-kill'.
>>
>> In this case you wouldn't like to replace the key binding, it would affect all
>> org-capture buffers; the point is just to replace it when called in certain
>> context (my-read-line). Let-binding the function in this context achieves
>> exactly the same effect of C-c C-c beng bound to my function but without
>> affecting all org-capture-buffers.
>
> The hook `org-capture-mode-hook' will be run in your special
> capture buffer. You can override the "C-c C-c" binding only there.

Yes and in every other capture buffer, so I would either have to test on some
variable, make another mode, or mode-map or something similar. Just to customize
on the key, instead of the value bound to that key.

>>
>> Yes, I am aware of both hooks and advising; but again, with those I would affect
>> all uses of the function, and that would lead to checking some global state or
>> variable to switch on, which is not optimal either. With let-binding we can have
>> different behaviour only in a certain context.
>
> Even if I could let bind the function at the right time, I would avoid
> that solution, as I can't garantuee that this global hack will not break
> other parts of Emacs (other captures, output filters, threads, timers,
> etc.).

Why do you think it will break other parts? This is not a global hack, on contrary it
exactly tries to prevent to be "global" in entire Emacs, by let-binding a name
to a local lambda, which becomes "global" only in that buffer. If that
explains.

Here is another version on the same theme, where I don't think you could modify the local
environment without let-binding at all:

#+begin_src emacs-lisp
(defun my-read-string (prompt)
  (let ((delta 20 )
        (minibuffer-mode-map org-mode-map))
    (window-resize (minibuffer-window) delta)
    (cl-letf (((symbol-function 'org-ctrl-c-ctrl-c)
               (lambda ()
                 (interactive)
                 (let ((s (buffer-string)))
                   (exit-minibuffer) s)))
              ((symbol-function 'minibuffer-mode) #'org-mode)
              ((symbol-function 'minibuffer-complete-and-exit) #'org-return)
              ((symbol-function 'org-kill-note-or-show-branches) #'keyboard-escape-quit))
      (read-string (concat "# Press C-c C-c to continue, C-c C-k to cancel\n# " prompt "\n\n")))))
#+end_src

read-string is written in C and creates its own minibuffer, which is deleted by
the time read-string exits. I don't know of any other way to cutomize exactly
*that* minibuffer, without installing a hook or advising some functions, which I
think is way less clean and much more "global" than just running the function in
a local environment. As I understand, let binding for this purpose is a normal
technique in lisps, but I am not an expert as said; I am actually experimenting
with this for the purpose of learning and seeing what is possible.

Of course, we can always write our own read-string function and re-implement the
function from scratch, which author of that blog actually did. The experiment
was to test if I can modify the existing functionality to re-use, rather than to
re-invent something. Since read-string functions does not let us specify buffer,
mode, etc, let binding is one way of doing it locally.

Considering how org-capture works, the same technique of just modifying the
local environment is not really applicable; now when you reminded me that
capture buffer lives longer then let-binding, I understand what happens. I can
access the buffer after org-capture exits, in my-read-string:

    (with-current-buffer
        (try-completion "CAPTURE" (mapcar #'buffer-name (buffer-list)))
         ( .... do the thng .... )

but I am not sure if I can do anything here without introducing at-least an
extra keymap, to not install into the org-capture-mode-map, so I can as well
create a minor mode, but at this point it is not much different than
re-invinting the read-string, so I'll terminate my experiment here :).

But I wouldn't speak in some generic terms like "use hooks" or "advise" instead
of let-binding. Let binding is a powerful and legitimate technique to modify
local environment of functions. I am not really sure where it stands in
abstraction, if it is sort-of template, or interface programming, since I am not
that familiar with lisp (yet), but I do understand it has very good and powerful
uses. Consider this (you can actually eval an run from gnus, or in scartch):

#+begin_src emacs-lisp
;;;; Project folder - org-capture related code
(defvar org-project-root-dir nil)
(defvar org-project-templates nil)
(defvar org-project-finalize-hooks nil)

(setq org-project-templates
      `(("W" "Web Projects")
        ("Wb" "Bootstrap Project" plain
         (function org-project-new)
         "A Bootstrap Project")
        ("Wh" "Web project" plain
         (function org-project-new)
         "Simple HTML Project")
        ("C" "C/C++ Projects")
        ("Cc" "C Console Project" plain
         (function org-project-new)
         "A Command Line Project with C")
        ("CC" "C++ Console Project" plain
         (function org-project-new)
         "A Command Line Project with C++")
        ("CG" "C++ GLUT Project" plain
         (function org-project-new)
         "Simple GLUT Project")
        ("CQ" "C++ Qt Project" plain
         (function org-project-new)
         "Qt Project")
        ("CK" "C++ Qt Quick Project" plain
         (function org-project-new)
         "Qt Quick Project")))

(defun org-project-new-project ()
  (interactive)
  (let ((org-capture-templates org-project-templates))
    (org-capture)))

(define-key global-map (kbd "C-S-n") #'org-project-new-project)


(defun org-project-new ()
  "Interactively create new directory for a project.

Directory should not exist prior to call to this function."
  (let ((project-path (read-file-name "Project name: "
                                      org-project-root-dir
                                      nil nil nil)))
    (cond ((not (file-directory-p project-path))
           (make-directory project-path)
           (let ((file-name (concat (file-name-nondirectory project-path) ".org")))
             (find-file (expand-file-name  file-name project-path))
             (goto-char (point-min))))
          (t (message "Directory %s already exists." project-path))))
  (if org-project-finalize-hooks (run-hooks org-project-finalize-hooks)))
#+end_src

The only extra work I did, was to actually create an interactive function to
specify a path, and I can re-use both org-capture template language and
interactive functionality already built into the org-capture. I get an entire
framework for free :). The real action is happening in hooks, where I init git,
copy some templates, license and some other boiler-plate stuff.

I don't know what would be the alternative, but let-binding on
org-capture-templates, let me clearly re-use the functionality without polluting
the global org-capture-templates variable and without re-implementing pretty
much anything.

As I understand, let binding is useful in lisp, and as legitimate technique as
hooks, or advices. As said, I am not an expert, but I think, it is probably
preferrable to advising, where possible, since advising is global to all
function instances, while let-binding affects only local function instances, if
I can borrow some of OOP terms here.

I am very interested to hear more on the topic, since I would definitely like to
learn more about different techniques.

Hope that explains a bit more on the background of the experiment :).

best regards
/a


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-10 15:05 Problem with let/cl-letf binding stuff with org-capture Arthur Miller
  2023-02-10 15:38 ` Ruijie Yu via General discussions about Org-mode.
  2023-02-10 19:00 ` Bruno Barbier
@ 2023-02-11 16:49 ` Ihor Radchenko
  2023-02-15 13:06   ` Arthur Miller
  2 siblings, 1 reply; 19+ messages in thread
From: Ihor Radchenko @ 2023-02-11 16:49 UTC (permalink / raw)
  To: Arthur Miller; +Cc: emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

> Based on a Reddit thread:
>
> https://www.reddit.com/r/emacs/comments/10xhvd8/a_little_readstring_utility_using_an_org_mode/j7xziao/?context=3
>
> I did a small experiment to see if I can re-use org-capture, to just capture a
> string from a buffer, without actually writing to any file.

You can use a template target set to function pointing to temporary
buffer. + org-capture-before-finalize-hook

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-11 16:14       ` Arthur Miller
@ 2023-02-11 19:23         ` Bruno Barbier
  2023-02-12  7:21           ` Arthur Miller
  0 siblings, 1 reply; 19+ messages in thread
From: Bruno Barbier @ 2023-02-11 19:23 UTC (permalink / raw)
  To: Arthur Miller; +Cc: emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

> Bruno Barbier <brubar.cs@gmail.com> writes:
>
>> Arthur Miller <arthur.miller@live.com> writes:
>>
>> The hook `org-capture-mode-hook' will be run in your special
>> capture buffer. You can override the "C-c C-c" binding only there.
>
> Yes and in every other capture buffer

No. If you modify the hook only during your call to 'org-capture', it
will be called only once in your buffer.

>> Even if I could let bind the function at the right time, I would avoid
>> that solution, as I can't garantuee that this global hack will not break
>> other parts of Emacs (other captures, output filters, threads, timers,
>> etc.).
>
> Why do you think it will break other parts? This is not a global hack, on contrary it
> exactly tries to prevent to be "global" in entire Emacs, by let-binding a name
> to a local lambda, which becomes "global" only in that buffer. If that
> explains.

You are assigning a local value to the global binding. Everything in
Emacs will use your functions until you exit the cl-letf. It's like if
you were using 'fset'.

Here is an example that uses cl-letf. Note that the call to
async-shell-command is outside the "local" binding, yet, the cl-letf
breaks it. You should try this in an other Emacs, just in case.

(defun oops ()
  (let ((v (async-shell-command "date" "!sh async")))
    (cl-letf
        (((symbol-function 'comint-output-filter)
          (lambda (proc string)
            (message "async-shell-command is using my binding: %s" string)
            (read-string "What's the password?"))))
      (read-string "what: ")
      )))
(oops)


>
> Here is another version on the same theme, where I don't think you could modify the local
> environment without let-binding at all:
>
> #+begin_src emacs-lisp
> (defun my-read-string (prompt)
>   (let ((delta 20 )
>         (minibuffer-mode-map org-mode-map))
>     (window-resize (minibuffer-window) delta)
>     (cl-letf (((symbol-function 'org-ctrl-c-ctrl-c)
>                (lambda ()
>                  (interactive)
>                  (let ((s (buffer-string)))
>                    (exit-minibuffer) s)))
>               ((symbol-function 'minibuffer-mode) #'org-mode)
>               ((symbol-function 'minibuffer-complete-and-exit) #'org-return)
>               ((symbol-function 'org-kill-note-or-show-branches) #'keyboard-escape-quit))
>       (read-string (concat "# Press C-c C-c to continue, C-c C-k to cancel\n# " prompt "\n\n")))))
> #+end_src

I hope I've convinced you to not do that. I definitely will not try it,
as Emacs needs a working minibuffer for plenty of things: debugging,
saving, quitting, etc.


> read-string is written in C and creates its own minibuffer, which is deleted by
> the time read-string exits. I don't know of any other way to cutomize exactly
> *that* minibuffer, without installing a hook or advising some functions, which I
> think is way less clean and much more "global" than just running the function in
> a local environment. As I understand, let binding for this purpose is a normal
> technique in lisps, but I am not an expert as said; I am actually experimenting
> with this for the purpose of learning and seeing what is possible.

Yes, let binding is fundamental. But I think it's the first time I see
'cl-letf' with the 'symbol-function' place.


> ...
> but I am not sure if I can do anything here without introducing at-least an
> extra keymap, to not install into the org-capture-mode-map, so I can as well
> create a minor mode, but at this point it is not much different than
> re-invinting the read-string, so I'll terminate my experiment here :).

You can replace the buffer keymap with a keymap that only contain your custom
keys, and inherits everything else from org-capture-mode-map.


>
> But I wouldn't speak in some generic terms like "use hooks" or "advise" instead
> of let-binding.

I didn't mean to say to not use let bindings. I'm trying to say that
using 'fset' (i.e. cl-letf + the symbol-function place) looks like a
really bad idea to me. And, in this case, hooks and adivces are what is
usually used.



> (defun org-project-new-project ()
>   (interactive)
>   (let ((org-capture-templates org-project-templates))
>     (org-capture)))
>
> ...

> I don't know what would be the alternative, but let-binding on
> org-capture-templates, let me clearly re-use the functionality without polluting
> the global org-capture-templates variable and without re-implementing pretty
> much anything.

That looks to me like a perfect use of a let binding.  You bind a dynamic
*variable* using *let*, and, that variable is rebound, and used, during, and
only during 'org-capture'.



> I am very interested to hear more on the topic, since I would definitely like to
> learn more about different techniques.

Variables are designed to be overriden (let bounds). Functions are not
(as there is only one binding at any given time).


> Hope that explains a bit more on the background of the experiment :).

I'm still confused about the idea of making 'read-string' behave like
'org-capture', but, we use Emacs because we can experiment! No need for
justification ;-)

And, experimenting with the minibuffer, which is one of the fundamental
component to control Emacs, that's definitely courageous :-)

best,

Bruno


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-11 19:23         ` Bruno Barbier
@ 2023-02-12  7:21           ` Arthur Miller
  2023-02-12  9:22             ` Bruno Barbier
  0 siblings, 1 reply; 19+ messages in thread
From: Arthur Miller @ 2023-02-12  7:21 UTC (permalink / raw)
  To: Bruno Barbier; +Cc: emacs-orgmode

Bruno Barbier <brubar.cs@gmail.com> writes:

> Arthur Miller <arthur.miller@live.com> writes:
>
>> Bruno Barbier <brubar.cs@gmail.com> writes:
>>
>>> Arthur Miller <arthur.miller@live.com> writes:
>>>
>>> The hook `org-capture-mode-hook' will be run in your special
>>> capture buffer. You can override the "C-c C-c" binding only there.
>>
>> Yes and in every other capture buffer
>
> No. If you modify the hook only during your call to 'org-capture', it
> will be called only once in your buffer.
>
>>> Even if I could let bind the function at the right time, I would avoid
>>> that solution, as I can't garantuee that this global hack will not break
>>> other parts of Emacs (other captures, output filters, threads, timers,
>>> etc.).
>>
>> Why do you think it will break other parts? This is not a global hack, on contrary it
>> exactly tries to prevent to be "global" in entire Emacs, by let-binding a name
>> to a local lambda, which becomes "global" only in that buffer. If that
>> explains.
>
> You are assigning a local value to the global binding. Everything in
> Emacs will use your functions until you exit the cl-letf. It's like if
> you were using 'fset'.

Yes, you are totally correct; unfortunately binding with cl-flet or cl-labels,
does not work, so binding the global is the only one that works.

> Here is an example that uses cl-letf. Note that the call to
> async-shell-command is outside the "local" binding, yet, the cl-letf
> breaks it. You should try this in an other Emacs, just in case.
>
> (defun oops ()
>   (let ((v (async-shell-command "date" "!sh async")))
>     (cl-letf
>         (((symbol-function 'comint-output-filter)
>           (lambda (proc string)
>             (message "async-shell-command is using my binding: %s" string)
>             (read-string "What's the password?"))))
>       (read-string "what: ")
>       )))
> (oops)

Yes, I definitely agree with you about the concerns, which are certainly
valid, but you would get same effect with advice, it is not different at
all. The difference is that let-binding is automatically removed and installed,
and only active during the cl-letf, while advice is manually installed and
active until manually removed. It is not about the tool, but what you do with
the tool.

>> Here is another version on the same theme, where I don't think you could modify the local
>> environment without let-binding at all:
>>
>> #+begin_src emacs-lisp
>> (defun my-read-string (prompt)
>>   (let ((delta 20 )
>>         (minibuffer-mode-map org-mode-map))
>>     (window-resize (minibuffer-window) delta)
>>     (cl-letf (((symbol-function 'org-ctrl-c-ctrl-c)
>>                (lambda ()
>>                  (interactive)
>>                  (let ((s (buffer-string)))
>>                    (exit-minibuffer) s)))
>>               ((symbol-function 'minibuffer-mode) #'org-mode)
>>               ((symbol-function 'minibuffer-complete-and-exit) #'org-return)
>>               ((symbol-function 'org-kill-note-or-show-branches) #'keyboard-escape-quit))
>>       (read-string (concat "# Press C-c C-c to continue, C-c C-k to cancel\n# " prompt "\n\n")))))
>> #+end_src
>
> I hope I've convinced you to not do that. I definitely will not try it,
> as Emacs needs a working minibuffer for plenty of things: debugging,
> saving, quitting, etc.

Your minibuffer will continue to work during and after that function. If you
don't use recursive minibuffer, that will only affect the internal buffer
created by read-string.

If recursive minibuffer is enabled, yes they will also be affected. Of course,
there is no reason for you to try that, that was just an example, but I feel a
bit of passive aggressivity here, for no good reason tbh.

>> read-string is written in C and creates its own minibuffer, which is deleted by
>> the time read-string exits. I don't know of any other way to cutomize exactly
>> *that* minibuffer, without installing a hook or advising some functions, which I
>> think is way less clean and much more "global" than just running the function in
>> a local environment. As I understand, let binding for this purpose is a normal
>> technique in lisps, but I am not an expert as said; I am actually experimenting
>> with this for the purpose of learning and seeing what is possible.
>
> Yes, let binding is fundamental. But I think it's the first time I see
> 'cl-letf' with the 'symbol-function' place.

https://nullprogram.com/blog/2017/10/27/
https://endlessparentheses.com/understanding-letf-and-how-it-replaces-flet.html
https://stackoverflow.com/questions/39550578/in-emacs-what-is-the-difference-between-cl-flet-and-cl-letf

>> but I am not sure if I can do anything here without introducing at-least an
>> extra keymap, to not install into the org-capture-mode-map, so I can as well
>> create a minor mode, but at this point it is not much different than
>> re-invinting the read-string, so I'll terminate my experiment here :).
>
> You can replace the buffer keymap with a keymap that only contain your custom
> keys, and inherits everything else from org-capture-mode-map.

Isn't that what I wrote: introducing an extra keymap?

Of course I can solve the problem differently, but that was not what question
was about :).

>> But I wouldn't speak in some generic terms like "use hooks" or "advise" instead
>> of let-binding.
>
> I didn't mean to say to not use let bindings. I'm trying to say that
> using 'fset' (i.e. cl-letf + the symbol-function place) looks like a
> really bad idea to me.

Well, I definitely understand you, and agree that overwriting function for
everyone and everything is not the best idea, but unfortunately bindings work as
they do in Emacs. I would prefer to have a local binding, with cl-flet, but this
does not work in Emacs:

(defun my-read-string (prompt)
  (let ((delta 20 )
        (minibuffer-mode-map org-mode-map))
    (window-resize (minibuffer-window) delta)
    (cl-flet ((org-ctrl-c-ctrl-c ()
                (interactive)
                (let ((s (buffer-string)))
                  (exit-minibuffer) s))
              (minibuffer-mode () #'org-mode)
              (minibuffer-complete-and-exit () #'org-return)
              (org-kill-note-or-show-branches () #'keyboard-escape-quit))
      (read-string (concat "# Press C-c C-c to continue, C-c C-k to cancel\n# "
  prompt "\n\n")))))

>                        And, in this case, hooks and adivces are what is
> usually used.

Hooks serve a different purpose. Advice can serve same purpose with exactly
same side effect, and some other limitations. With some care, let-binding is
still more "local" then advice. With other words, I agree with you about the
problems, but not with dogmatic approach that it should never be done, and
that hooks and advices are the replacement.

>> (defun org-project-new-project ()
>>   (interactive)
>>   (let ((org-capture-templates org-project-templates))
>>     (org-capture)))
>>
>> ...
>
>> I don't know what would be the alternative, but let-binding on
>> org-capture-templates, let me clearly re-use the functionality without polluting
>> the global org-capture-templates variable and without re-implementing pretty
>> much anything.
>
> That looks to me like a perfect use of a let binding.  You bind a dynamic
> *variable* using *let*, and, that variable is rebound, and used, during, and
> only during 'org-capture'.
>
>
>
>> I am very interested to hear more on the topic, since I would definitely like to
>> learn more about different techniques.
>
> Variables are designed to be overriden (let bounds). Functions are not

I have never heard before that functions are not designed to be overriden. I
think of them as two slots in a symbol structure; let creates bindings for value
slot, and flet for function slot. Functions are just objects or data as any
other value in lisp.

> (as there is only one binding at any given time).

Yes, unfortunately, in Emacs it is so; but I don't think it should be :).

There is an interesting package by Nick Ferrier

https://github.com/nicferrier/emacs-noflet

but it does not seem to work, at least not for me.

regards
/a


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-12  7:21           ` Arthur Miller
@ 2023-02-12  9:22             ` Bruno Barbier
  2023-02-12 16:12               ` Arthur Miller
  0 siblings, 1 reply; 19+ messages in thread
From: Bruno Barbier @ 2023-02-12  9:22 UTC (permalink / raw)
  To: Arthur Miller; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 4014 bytes --]


Hi Arthur,

Arthur Miller <arthur.miller@live.com> writes:

> Bruno Barbier <brubar.cs@gmail.com> writes:
>
> ...  but I feel a
> bit of passive aggressivity here, for no good reason tbh.

I'm just trying to help, giving some valid or invalid advices.  I'm
sorry that what I wrote, and how I wrote it, made you feel that way.

>>
>> Yes, let binding is fundamental. But I think it's the first time I see
>> 'cl-letf' with the 'symbol-function' place.
>
> https://nullprogram.com/blog/2017/10/27/
> https://endlessparentheses.com/understanding-letf-and-how-it-replaces-flet.html
> https://stackoverflow.com/questions/39550578/in-emacs-what-is-the-difference-between-cl-flet-and-cl-letf
>

Thanks for these links. I like cl-flet and cl-labels :-)


>>> but I am not sure if I can do anything here without introducing at-least an
>>> extra keymap, to not install into the org-capture-mode-map, so I can as well
>>> create a minor mode, but at this point it is not much different than
>>> re-invinting the read-string, so I'll terminate my experiment here :).
>>
>> You can replace the buffer keymap with a keymap that only contain your custom
>> keys, and inherits everything else from org-capture-mode-map.
>
> Isn't that what I wrote: introducing an extra keymap?
> Of course I can solve the problem differently, but that was not what question
> was about :).

Right. Even when inheriting from the old keymap, it's still building a
new keymap.  Sorry :-)


> Well, I definitely understand you, and agree that overwriting function for
> everyone and everything is not the best idea, but unfortunately bindings work as
> they do in Emacs. I would prefer to have a local binding, with cl-flet, but this
> does not work in Emacs:
>
> (defun my-read-string (prompt)
>   (let ((delta 20 )
>         (minibuffer-mode-map org-mode-map))
>     (window-resize (minibuffer-window) delta)
>     (cl-flet ((org-ctrl-c-ctrl-c ()
>                 (interactive)
>                 (let ((s (buffer-string)))
>                   (exit-minibuffer) s))
>               (minibuffer-mode () #'org-mode)
>               (minibuffer-complete-and-exit () #'org-return)
>               (org-kill-note-or-show-branches () #'keyboard-escape-quit))
>       (read-string (concat "# Press C-c C-c to continue, C-c C-k to cancel\n# "
>   prompt "\n\n")))))

Yes. cl-flet looks safe to me :-)

>
> Hooks serve a different purpose. Advice can serve same purpose with exactly
> same side effect, and some other limitations. With some care, let-binding is
> still more "local" then advice. With other words, I agree with you about the
> problems, but not with dogmatic approach that it should never be done, and
> that hooks and advices are the replacement.

Sorry if my words sounding dogmatic.
Else, I agree too :-)


>>
>>> I am very interested to hear more on the topic, since I would definitely like to
>>> learn more about different techniques.
>>
>> Variables are designed to be overriden (let bounds). Functions are not
>
> I have never heard before that functions are not designed to be overriden. I
> think of them as two slots in a symbol structure; let creates bindings for value
> slot, and flet for function slot. Functions are just objects or data as any
> other value in lisp.
>
>> (as there is only one binding at any given time).
>
> Yes, unfortunately, in Emacs it is so;

ok. We do really agree then :-)


> but I don't think it should be > :).

... oh no ! ;-)


>
> There is an interesting package by Nick Ferrier
>
> https://github.com/nicferrier/emacs-noflet

> but it does not seem to work, at least not for me.

It's almost like a temporary advice ;-)


About your use case, if what you need is asynchronous editing, maybe the
with-editor package will be of interest to you:
    https://github.com/magit/with-editor/blob/main/lisp/with-editor.el
    
It allows sub-processes to call Emacs for editing tasks. It's used by
magit. It's easy enough to reuse. I've attached my attempt at it if
you're interested.

best,

Bruno


[-- Attachment #2: my-edit-async draft --]
[-- Type: text/plain, Size: 1563 bytes --]

(cl-defun my-edit-async (finish &key mode buffer-name setup cancel)
  "Open a buffer, let the user edit its content.
Return the editing buffer.  Call FINISH in the editing buffer if
the user validates his edit (C-c C-c).  When CANCEL is non-nil,
call CANCEL in the editing buffer if the user cancels his
edit (C-c C-k). When done, delete the buffer and its content.

When MODE is non-nil, use it as the major-mode.  When BUFFER-NAME
is non-nil, use it to generate a new unique name of the editing buffer.
When SETUP is non-nil, call it in the edit buffer to setup the
buffer before starting the edit."
  (unless buffer-name (setq buffer-name "@Async edit"))
  (let ((buf (generate-new-buffer buffer-name)))
    (with-current-buffer buf
      (when mode (funcall mode))
      (when setup
        (funcall setup))
      (with-editor-mode 1)
      (setq with-editor-previous-winconf
            (current-window-configuration))
      (add-hook 'with-editor-pre-finish-hook
                (lambda () 
                  (funcall finish)
                  (set-buffer-modified-p nil))
                nil :local)
      (add-hook 'with-editor-pre-cancel-hook
                (lambda ()
                  (when cancel (funcall cancel))
                  (set-buffer-modified-p nil))
                nil :local)
      (switch-to-buffer buf))
    buf))

(my-edit-async 
 (lambda () (message "My edit:\n%S" (buffer-string)))
 :cancel (lambda () (message "Canceled (discarded: %s)" (buffer-string)))
 :setup (lambda () (insert "initial content") (goto-char (point-min))))




[-- Attachment #3: Type: text/plain, Size: 22 bytes --]








> regards
> /a

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-12  9:22             ` Bruno Barbier
@ 2023-02-12 16:12               ` Arthur Miller
  2023-02-12 16:22                 ` Ihor Radchenko
  2023-02-13 18:37                 ` Bruno Barbier
  0 siblings, 2 replies; 19+ messages in thread
From: Arthur Miller @ 2023-02-12 16:12 UTC (permalink / raw)
  To: Bruno Barbier; +Cc: emacs-orgmode

Bruno Barbier <brubar.cs@gmail.com> writes:

> Hi Arthur,
>
> Arthur Miller <arthur.miller@live.com> writes:
>
>> Bruno Barbier <brubar.cs@gmail.com> writes:
>>
>> ...  but I feel a
>> bit of passive aggressivity here, for no good reason tbh.
>
> I'm just trying to help, giving some valid or invalid advices.  I'm
> sorry that what I wrote, and how I wrote it, made you feel that way.

It is ok, I just don't want us to go into social media discussion style where
there is more important to assert own ego then to come into some insight.

>>>
>>> Yes, let binding is fundamental. But I think it's the first time I see
>>> 'cl-letf' with the 'symbol-function' place.
>>
>> https://nullprogram.com/blog/2017/10/27/
>> https://endlessparentheses.com/understanding-letf-and-how-it-replaces-flet.html
>> https://stackoverflow.com/questions/39550578/in-emacs-what-is-the-difference-between-cl-flet-and-cl-letf
>>
>
> Thanks for these links. I like cl-flet and cl-labels :-)

They are good for introducing *new* bindings, not so for overriding locally.

>>>> but I am not sure if I can do anything here without introducing at-least an
>>>> extra keymap, to not install into the org-capture-mode-map, so I can as well
>>>> create a minor mode, but at this point it is not much different than
>>>> re-invinting the read-string, so I'll terminate my experiment here :).
>>>
>>> You can replace the buffer keymap with a keymap that only contain your custom
>>> keys, and inherits everything else from org-capture-mode-map.
>>
>> Isn't that what I wrote: introducing an extra keymap?
>> Of course I can solve the problem differently, but that was not what question
>> was about :).
>
> Right. Even when inheriting from the old keymap, it's still building a
> new keymap.  Sorry :-)
>
>
>> Well, I definitely understand you, and agree that overwriting function for
>> everyone and everything is not the best idea, but unfortunately bindings work as
>> they do in Emacs. I would prefer to have a local binding, with cl-flet, but this
>> does not work in Emacs:
>>
>> (defun my-read-string (prompt)
>>   (let ((delta 20 )
>>         (minibuffer-mode-map org-mode-map))
>>     (window-resize (minibuffer-window) delta)
>>     (cl-flet ((org-ctrl-c-ctrl-c ()
>>                 (interactive)
>>                 (let ((s (buffer-string)))
>>                   (exit-minibuffer) s))
>>               (minibuffer-mode () #'org-mode)
>>               (minibuffer-complete-and-exit () #'org-return)
>>               (org-kill-note-or-show-branches () #'keyboard-escape-quit))
>>       (read-string (concat "# Press C-c C-c to continue, C-c C-k to cancel\n# "
>>   prompt "\n\n")))))
>
> Yes. cl-flet looks safe to me :-)
>
>>
>> Hooks serve a different purpose. Advice can serve same purpose with exactly
>> same side effect, and some other limitations. With some care, let-binding is
>> still more "local" then advice. With other words, I agree with you about the
>> problems, but not with dogmatic approach that it should never be done, and
>> that hooks and advices are the replacement.
>
> Sorry if my words sounding dogmatic.
> Else, I agree too :-)
>
>
>>>
>>>> I am very interested to hear more on the topic, since I would definitely like to
>>>> learn more about different techniques.
>>>
>>> Variables are designed to be overriden (let bounds). Functions are not
>>
>> I have never heard before that functions are not designed to be overriden. I
>> think of them as two slots in a symbol structure; let creates bindings for value
>> slot, and flet for function slot. Functions are just objects or data as any
>> other value in lisp.
>>
>>> (as there is only one binding at any given time).
>>
>> Yes, unfortunately, in Emacs it is so;
>
> ok. We do really agree then :-)
>
>
>> but I don't think it should be > :).
>
> ... oh no ! ;-)
>
>
>>
>> There is an interesting package by Nick Ferrier
>>
>> https://github.com/nicferrier/emacs-noflet
>
>> but it does not seem to work, at least not for me.
>
> It's almost like a temporary advice ;-)
>
>
> About your use case, if what you need is asynchronous editing, maybe the
> with-editor package will be of interest to you:
>     https://github.com/magit/with-editor/blob/main/lisp/with-editor.el
>     
> It allows sub-processes to call Emacs for editing tasks. It's used by
> magit. It's easy enough to reuse. I've attached my attempt at it if
> you're interested.
>
> best,
>
> Bruno
>
> (cl-defun my-edit-async (finish &key mode buffer-name setup cancel)
>   "Open a buffer, let the user edit its content.
> Return the editing buffer.  Call FINISH in the editing buffer if
> the user validates his edit (C-c C-c).  When CANCEL is non-nil,
> call CANCEL in the editing buffer if the user cancels his
> edit (C-c C-k). When done, delete the buffer and its content.
>
> When MODE is non-nil, use it as the major-mode.  When BUFFER-NAME
> is non-nil, use it to generate a new unique name of the editing buffer.
> When SETUP is non-nil, call it in the edit buffer to setup the
> buffer before starting the edit."
>   (unless buffer-name (setq buffer-name "@Async edit"))
>   (let ((buf (generate-new-buffer buffer-name)))
>     (with-current-buffer buf
>       (when mode (funcall mode))
>       (when setup
>         (funcall setup))
>       (with-editor-mode 1)
>       (setq with-editor-previous-winconf
>             (current-window-configuration))
>       (add-hook 'with-editor-pre-finish-hook
>                 (lambda () 
>                   (funcall finish)
>                   (set-buffer-modified-p nil))
>                 nil :local)
>       (add-hook 'with-editor-pre-cancel-hook
>                 (lambda ()
>                   (when cancel (funcall cancel))
>                   (set-buffer-modified-p nil))
>                 nil :local)
>       (switch-to-buffer buf))
>     buf))
>
> (my-edit-async 
>  (lambda () (message "My edit:\n%S" (buffer-string)))
>  :cancel (lambda () (message "Canceled (discarded: %s)" (buffer-string)))
>  :setup (lambda () (insert "initial content") (goto-char (point-min))))
>

That looks very nice indeed. I am not aware of that package, I will definitely
use it somewhere, sometime. But with that we are getting now into 1K extra sloc
solution. With this experiment, I was mostly interesting to see how I can re-use
what already is in Emacs. Lisps are great for prototyping and writing new
software. Legend says that Steele was cranking out 10 intepreters a week at his
time :). I don't know how true it is, just read it in some blog, but the
point is that we are rather typing fast new pieces instead of learning how
to re-use stuff, which in the long run I believe is a bad habit, since we are
debugging bits that does the same what someone else already debugged. Don't get
me wrong, I have nothing against using someones package, certainly not
with-editor, seems like a good package; I am just talking about programming in
general.

This was also me trying to get better in Emacs Lisp, but I have to admit I am a
bit dissapointed we can't just override function bindings with cl-flet. Function
slot is just another slot :).

I am using cl-labels and cl-flet myself to introduce "local" functions, to not
pollute global namespace (symbol table), which they are good for, and to keep
code local where it is used, and I think they are also slightly more clear then
lambdas. They are good for that, unfortunately it is a bit of dissapoitment that
we can't locally bind functions slots other then actually overriding them globally.

And for the last time: I am not using this version of read-string, I don't need
it myself; it was just me thinking how to implement something after reading a
blog post. Anyway, thanks for the input, it was valuable to me.

regards
/a


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-12 16:12               ` Arthur Miller
@ 2023-02-12 16:22                 ` Ihor Radchenko
  2023-02-13 18:40                   ` Bruno Barbier
  2023-02-13 18:37                 ` Bruno Barbier
  1 sibling, 1 reply; 19+ messages in thread
From: Ihor Radchenko @ 2023-02-12 16:22 UTC (permalink / raw)
  To: Arthur Miller; +Cc: Bruno Barbier, emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

> And for the last time: I am not using this version of read-string, I don't need
> it myself; it was just me thinking how to implement something after reading a
> blog post. Anyway, thanks for the input, it was valuable to me.

Note that Emacs 29 has `read-string-from-buffer'.
 
-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-12 16:12               ` Arthur Miller
  2023-02-12 16:22                 ` Ihor Radchenko
@ 2023-02-13 18:37                 ` Bruno Barbier
  1 sibling, 0 replies; 19+ messages in thread
From: Bruno Barbier @ 2023-02-13 18:37 UTC (permalink / raw)
  To: Arthur Miller; +Cc: emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

> Bruno Barbier <brubar.cs@gmail.com> writes:
>
>>
>
> That looks very nice indeed. I am not aware of that package, I will definitely
> use it somewhere, sometime. But with that we are getting now into 1K extra sloc
> solution. With this experiment, I was mostly interesting to see how I can re-use
> what already is in Emacs. Lisps are great for prototyping and writing new
> software. Legend says that Steele was cranking out 10 intepreters a week at his
> time :). I don't know how true it is, just read it in some blog, but the
> point is that we are rather typing fast new pieces instead of learning how
> to re-use stuff, which in the long run I believe is a bad habit, since we are
> debugging bits that does the same what someone else already debugged. Don't get
> me wrong, I have nothing against using someones package, certainly not
> with-editor, seems like a good package; I am just talking about programming in
> general.

... And the piece of code, that I just wrote and sent, was already
available in Emacs (see Ihor's email). I've definitely failed to do my
research before coding ... I definitely get your point! :-)

> This was also me trying to get better in Emacs Lisp, but I have to admit I am a
> bit dissapointed we can't just override function bindings with cl-flet. Function
> slot is just another slot :).
>
> I am using cl-labels and cl-flet myself to introduce "local" functions, to not
> pollute global namespace (symbol table), which they are good for, and to keep
> code local where it is used, and I think they are also slightly more clear then
> lambdas. They are good for that, unfortunately it is a bit of dissapoitment that
> we can't locally bind functions slots other then actually overriding them globally.

Since I've learned that cl-flet and cl-labels are local lexically, I'm
using them more and more: that removes lot of noisy funcalls, compare to
lambdas.


> And for the last time: I am not using this version of read-string, I don't need
> it myself; it was just me thinking how to implement something after reading a
> blog post. Anyway, thanks for the input, it was valuable to me.

Got it. Thanks for your patience and your valuable inputs too.

And I'm definitely going to use the version that is in Emacs. Thanks for
this too.

best,

Bruno


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-12 16:22                 ` Ihor Radchenko
@ 2023-02-13 18:40                   ` Bruno Barbier
  2023-02-15 11:45                     ` Arthur Miller
  0 siblings, 1 reply; 19+ messages in thread
From: Bruno Barbier @ 2023-02-13 18:40 UTC (permalink / raw)
  To: Ihor Radchenko, Arthur Miller; +Cc: emacs-orgmode


Ihor Radchenko <yantar92@posteo.net> writes:

> Note that Emacs 29 has `read-string-from-buffer'.

I completely missed the fact that it was already in Emacs.

I'll definitely use the string-edit version (the version
with callbacks).

Thanks Ihor.

Bruno


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-13 18:40                   ` Bruno Barbier
@ 2023-02-15 11:45                     ` Arthur Miller
  2023-02-15 13:18                       ` Bruno Barbier
  0 siblings, 1 reply; 19+ messages in thread
From: Arthur Miller @ 2023-02-15 11:45 UTC (permalink / raw)
  To: Bruno Barbier; +Cc: Ihor Radchenko, emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 576 bytes --]

Bruno Barbier <brubar.cs@gmail.com> writes:

> Ihor Radchenko <yantar92@posteo.net> writes:
>
>> Note that Emacs 29 has `read-string-from-buffer'.
>
> I completely missed the fact that it was already in Emacs.
>
> I'll definitely use the string-edit version (the version
> with callbacks).
>
> Thanks Ihor.

Same here, very much thanks Ihor!

I postponed answering unitll i have testedit. Cool.

Now I have to say are you f-n kidding me :).

Anyway, a follow question: Where is the source code?!

Normally the help window says "... is a Lisp function in <some-source-file>."


[-- Attachment #2: no-source-link.png --]
[-- Type: image/png, Size: 152244 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-11 16:49 ` Ihor Radchenko
@ 2023-02-15 13:06   ` Arthur Miller
  0 siblings, 0 replies; 19+ messages in thread
From: Arthur Miller @ 2023-02-15 13:06 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

Ihor Radchenko <yantar92@posteo.net> writes:

> Arthur Miller <arthur.miller@live.com> writes:
>
>> Based on a Reddit thread:
>>
>> https://www.reddit.com/r/emacs/comments/10xhvd8/a_little_readstring_utility_using_an_org_mode/j7xziao/?context=3
>>
>> I did a small experiment to see if I can re-use org-capture, to just capture a
>> string from a buffer, without actually writing to any file.
>
> You can use a template target set to function pointing to temporary
> buffer. + org-capture-before-finalize-hook

I did try something this:

#+begin_src emacs-lisp
(defun my-func ()
  (with-current-buffer (get-buffer-create "my-capture-buffer")))

(defun my-hook ()
  (with-current-buffer 
      (try-completion "CAPTURE" (mapcar #'buffer-name (buffer-list)))
    (let ((content (buffer-string)))
      (kill-buffer)
      content)))

(defun my-read-string ()
  (let ((org-capture-templates
         `(("s" "string" plain (function my-func))))
        (org-capture-before-finalize-hook #'my-hook))
    (org-capture nil "s")))
#+end_src

But that does not work well, because capture will put buffer it is called from
as original buffer and write to that one. To prevent that I can call capture
from a temporary buffer:

#+begin_src emacs-lisp
(defun my-read-string ()
  (with-current-buffer (get-buffer-create "my-capture-buffer")
    (let ((org-capture-templates
           `(("s" "string" plain (function ignore))))
          (org-capture-before-finalize-hook #'my-hook))
      (org-capture nil "s"))))
#+end_src

but than capture complains about the buffer not being a file buffer, despite the
before finalize hook. I could point it to some temp file like /tmp/my-capture, by
manipulating capture plist myself, but it seems to be too expensive to create a
temp file just for a hack to read a string form a buffer. There is probably some
other way, but I give up here, especially since you point our
read-string-from-buffer :)

Anyway, thanks for the input and help.

/a


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: Problem with let/cl-letf binding stuff with org-capture
  2023-02-15 11:45                     ` Arthur Miller
@ 2023-02-15 13:18                       ` Bruno Barbier
  2023-02-15 17:36                         ` arthur miller
  0 siblings, 1 reply; 19+ messages in thread
From: Bruno Barbier @ 2023-02-15 13:18 UTC (permalink / raw)
  To: Arthur Miller; +Cc: Ihor Radchenko, emacs-orgmode

Arthur Miller <arthur.miller@live.com> writes:

>
> Anyway, a follow question: Where is the source code?!

lisp/textmodes/string-edit.el

> Normally the help window says "... is a Lisp function in <some-source-file>."
>

My Emacs tells me it's an autoloaded function with the usual link.

Bruno



^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: Problem with let/cl-letf binding stuff with org-capture
  2023-02-15 13:18                       ` Bruno Barbier
@ 2023-02-15 17:36                         ` arthur miller
  0 siblings, 0 replies; 19+ messages in thread
From: arthur miller @ 2023-02-15 17:36 UTC (permalink / raw)
  To: Bruno Barbier; +Cc: Ihor Radchenko, emacs-orgmode@gnu.org

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

Hemma.... thanks, for some reason, my Emacs does not display the link but it does for other functions. Strange.

Thanks for the help!


-------- Originalmeddelande --------
Från: Bruno Barbier <brubar.cs@gmail.com>
Datum: 2023-02-15 14:18 (GMT+01:00)
Till: Arthur Miller <arthur.miller@live.com>
Kopia: Ihor Radchenko <yantar92@posteo.net>, emacs-orgmode@gnu.org
Ämne: Re: Problem with let/cl-letf binding stuff with org-capture

Arthur Miller <arthur.miller@live.com> writes:

>
> Anyway, a follow question: Where is the source code?!

lisp/textmodes/string-edit.el

> Normally the help window says "... is a Lisp function in <some-source-file>."
>

My Emacs tells me it's an autoloaded function with the usual link.

Bruno


[-- Attachment #2: Type: text/html, Size: 1474 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2023-02-15 17:37 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-10 15:05 Problem with let/cl-letf binding stuff with org-capture Arthur Miller
2023-02-10 15:38 ` Ruijie Yu via General discussions about Org-mode.
2023-02-10 16:29   ` Arthur Miller
2023-02-10 19:00 ` Bruno Barbier
2023-02-11  6:33   ` Arthur Miller
2023-02-11  7:58     ` Bruno Barbier
2023-02-11 16:14       ` Arthur Miller
2023-02-11 19:23         ` Bruno Barbier
2023-02-12  7:21           ` Arthur Miller
2023-02-12  9:22             ` Bruno Barbier
2023-02-12 16:12               ` Arthur Miller
2023-02-12 16:22                 ` Ihor Radchenko
2023-02-13 18:40                   ` Bruno Barbier
2023-02-15 11:45                     ` Arthur Miller
2023-02-15 13:18                       ` Bruno Barbier
2023-02-15 17:36                         ` arthur miller
2023-02-13 18:37                 ` Bruno Barbier
2023-02-11 16:49 ` Ihor Radchenko
2023-02-15 13:06   ` Arthur Miller

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).