Bruno Barbier <brubar...@gmail.com> writes: > Arthur Miller <arthur.mil...@live.com> writes: > >>> Bruno Barbier <brubar...@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