unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A widget-based version of find-cmd
@ 2019-05-31  2:15 Michael Heerdegen
  2019-06-03 19:07 ` Stefan Monnier
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Heerdegen @ 2019-05-31  2:15 UTC (permalink / raw)
  To: Emacs Development

Hello,

I like the idea of find-cmd.el but it's worthless to me since I use find
not often enough to remember all the option names, how time specs work
etc.

That's why I plan a widget-based version where the user can compose the
find command by clicking around in a tree of widgets, all guided with
categories to choose from, annotations with doc etc.

I would like to extend find-cmd cause it already has a collection of
syntactical information about find options -- would that be acceptable?

Or would it be a better approach to try to somehow extract the
documentation of the options from the find man page?

Else, I would have to extend find-constituents with the annotations to
show in the selection menus.  The original `find-cmd' behavior would be
untouched, the new widget-based thing would just be an additional
fancy interface.

I'm currently struggling with the widget stuff however, mostly because I
struggle with the documentation.  What I basically need is to define a
widget type that let's you choose from a list of options.  Among them
are combiners like "or" that, when chosen, should provide a widget of
the same type.  My problem is that I run into an infinite recursion.  I
thought I can avoid that by constructing the widget deferred via
:convert-widget but that doesn't help.  Maybe :convert-widget is not for
that purpose (actually, then I don't get the purpose of :convert-widget
from the widget manual).

Here is what I have thrown together so far - the basic widget type
described above has the name "a":

#+begin_src emacs-lisp
;; -*- lexical-binding: t -*-

(require 'widget)
(require 'find-cmd)
(eval-when-compile (require 'wid-edit))

(defvar find-cmd-wg-main-widget nil)

(define-widget 'a 'editable-list
  "Doc..."
  :value "ignore"
  :convert-widget
  (lambda (widget)
    (widget-put
     widget
     :args (cl-flet ((just-true (lambda (_) t))
                     (value-get-1 (lambda (w) (list 'iname (widget-field-value-get w)))))
             `((menu-choice
                :args
                ,(append
                  (delq nil
                        (mapcar
                         (pcase-lambda ((and `(,name . ,(or (and (pred listp) `(,arity))
                                                            (let arity nil)))
                                             (let name-string (symbol-name name))))
                           (ignore name)
                           (and arity
                                (if (zerop arity)
                                    `(choice-item ,name-string)
                                  `(editable-field :menu-tag ,name-string
                                                   :validate ,#'just-true
                                                   :format ,(concat name-string ": %v")
                                                   :value-get ,#'value-get-1))))
                         find-constituents))
                  ;; (mapcar
                  ;;  (lambda (combiner)
                  ;;    `(a :tag ,(symbol-name combiner)))
                  ;;  '(or and not prune))
                  )))))
    widget))

(let ((buf (generate-new-buffer "*Widget Test*")))
  (pop-to-buffer buf)
  (kill-all-local-variables)
  (let ((inhibit-read-only t))
    (erase-buffer))
  (remove-overlays)
  (setq-local find-cmd-wg-main-widget (widget-create 'a))
  (use-local-map (let ((map (make-sparse-keymap)))
                   (set-keymap-parent map widget-keymap)
                   (define-key map [(control ?c) (control ?c)]
                     (lambda ()
                       (interactive)
                       (message "%s" (apply #'find-cmd (widget-value find-cmd-wg-main-widget)))))
                   map))
  (widget-setup))
#+end_src

If you comment out the commented stuff, you get the infinite recursion
problem.

BTW, apropos using C-c C-c, why is cus-edit stealing this key by doing

  (widget-put (get 'editable-field 'widget-type) :keymap custom-field-keymap)

AFAIU the editable-field widget is not only useful for custom?

TIA,

Michael.



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

* Re: A widget-based version of find-cmd
  2019-05-31  2:15 A widget-based version of find-cmd Michael Heerdegen
@ 2019-06-03 19:07 ` Stefan Monnier
  2019-06-03 20:41   ` Drew Adams
  2019-06-03 22:40   ` A widget-based version of find-cmd Michael Heerdegen
  0 siblings, 2 replies; 13+ messages in thread
From: Stefan Monnier @ 2019-06-03 19:07 UTC (permalink / raw)
  To: emacs-devel

> I like the idea of find-cmd.el but it's worthless to me since I use find
> not often enough to remember all the option names, how time specs work
> etc.
>
> That's why I plan a widget-based version where the user can compose the
> find command by clicking around in a tree of widgets, all guided with
> categories to choose from, annotations with doc etc.

I think I understand what you're after, but I'd like to clarify:
find-cmd lets you build a command using an Elisp expression, so it's
meant for use from Elisp code, rather than interactively.
Whereas you seem to be considering an interactive use case, right?

> I would like to extend find-cmd cause it already has a collection of
> syntactical information about find options -- would that be acceptable?

Yes, of course.  Another direction (complementary rather than opposed to
what you're suggesting) would be to extend Elisp's completion so it
understands `find-cmd` and hence gives you the valid completion after
you type `(find-cmd '(pru TAB`
[ Of course, we don't want elisp-mode.el to know about find-cmd.el,
  we'd instead want this to be modular; could be used for `rx` as well,
  for example.  ]

> Or would it be a better approach to try to somehow extract the
> documentation of the options from the find man page?

That'd be spiffy.

> I'm currently struggling with the widget stuff however, mostly because I
> struggle with the documentation.

I'm sending you all my psychic power.  I hope it helps.

> What I basically need is to define a
> widget type that let's you choose from a list of options.  Among them
> are combiners like "or" that, when chosen, should provide a widget of
> the same type.  My problem is that I run into an infinite recursion.  I
> thought I can avoid that by constructing the widget deferred via
> :convert-widget but that doesn't help.  Maybe :convert-widget is not for
> that purpose (actually, then I don't get the purpose of :convert-widget
> from the widget manual).

I think you're looking for the `lazy` widget.

> BTW, apropos using C-c C-c, why is cus-edit stealing this key by doing
>
>   (widget-put (get 'editable-field 'widget-type) :keymap custom-field-keymap)
>
> AFAIU the editable-field widget is not only useful for custom?

The Widgets code was written pretty much specifically for Customs, so
I'm not surprised if some parts are not cleanly separated.
Please mark them with a FIXME or fix them when you bump into them ;-)


        Stefan




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

* RE: A widget-based version of find-cmd
  2019-06-03 19:07 ` Stefan Monnier
@ 2019-06-03 20:41   ` Drew Adams
  2019-06-03 22:53     ` Michael Heerdegen
  2019-06-03 22:40   ` A widget-based version of find-cmd Michael Heerdegen
  1 sibling, 1 reply; 13+ messages in thread
From: Drew Adams @ 2019-06-03 20:41 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

> Yes, of course.  Another direction (complementary rather than opposed to
> what you're suggesting) would be to extend Elisp's completion so it
> understands `find-cmd` and hence gives you the valid completion after
> you type `(find-cmd '(pru TAB`

Yes, both would be useful additions.  Completion is
handy and quick.  On the other hand, it would be
good to be able to fill out a "dialog box" (widgets)
once, and have the same filled-out settings available
for subsequent reuse (until you change some of those
settings).

You can perhaps get somewhat the same advantage from
completion by using `M-p' to retrieve the last input
for each completion type (assuming they are on separate
minibuffer histories), but that's not quite as handy.

One of the advantages of a dialog box in such contexts
is setting it and reusing it for multiple search actions
(interspersed with other, non-search actions).  In fact,
that's about the only advantage I find for such a dialog
box.

In sum, when there are possibly a bunch of settings you
might fill out, Emacs should save them and offer them
to you again.  You should not need to fill out the same
choices multiple times consecutively.

> I'm sending you all my psychic power.  I hope it helps.

Ditto, FWIW.

> > What I basically need is to define a
> > widget type that let's you choose from a list of options.  Among them
> > are combiners like "or" that, when chosen, should provide a widget of
> > the same type.  My problem is that I run into an infinite recursion.  I
> > thought I can avoid that by constructing the widget deferred via
> > :convert-widget but that doesn't help.  Maybe :convert-widget is not for
> > that purpose (actually, then I don't get the purpose of :convert-widget
> > from the widget manual).
> 
> I think you're looking for the `lazy` widget.

Or maybe just split it up, having part of it use `repeat'?

Thanks for working on this, Michael.



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

* Re: A widget-based version of find-cmd
  2019-06-03 19:07 ` Stefan Monnier
  2019-06-03 20:41   ` Drew Adams
@ 2019-06-03 22:40   ` Michael Heerdegen
  1 sibling, 0 replies; 13+ messages in thread
From: Michael Heerdegen @ 2019-06-03 22:40 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> I think I understand what you're after, but I'd like to clarify:
> find-cmd lets you build a command using an Elisp expression, so it's
> meant for use from Elisp code, rather than interactively.
> Whereas you seem to be considering an interactive use case, right?

Exactly.  The main overlap with find-cmd is the inherent knowledge about
"find".

I want that a user can compose the "find" call with widgets and hit C-c
C-c or so to execute it.

> Yes, of course.  Another direction (complementary rather than opposed to
> what you're suggesting) would be to extend Elisp's completion so it
> understands `find-cmd` and hence gives you the valid completion after
> you type `(find-cmd '(pru TAB`
> [ Of course, we don't want elisp-mode.el to know about find-cmd.el,
>   we'd instead want this to be modular; could be used for `rx` as well,
>   for example.  ]

Something like that would be good, yes.

> I'm sending you all my psychic power.  I hope it helps.

I think it does.

> I think you're looking for the `lazy` widget.

Bingo!  Thanks.

> The Widgets code was written pretty much specifically for Customs, so
> I'm not surprised if some parts are not cleanly separated.
> Please mark them with a FIXME or fix them when you bump into them ;-)

Ok, will do.


Thanks,

Michael.



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

* Re: A widget-based version of find-cmd
  2019-06-03 20:41   ` Drew Adams
@ 2019-06-03 22:53     ` Michael Heerdegen
  2019-06-03 23:28       ` Drew Adams
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Heerdegen @ 2019-06-03 22:53 UTC (permalink / raw)
  To: Drew Adams; +Cc: Stefan Monnier, emacs-devel

Drew Adams <drew.adams@oracle.com> writes:

> One of the advantages of a dialog box in such contexts
> is setting it and reusing it for multiple search actions
> (interspersed with other, non-search actions).

Currently it's only planned to let the buffers stay alive.  I dunno if I
can save a buffer showing arbitrary widgets?  I guess I would have to
create the widget view from an internal representation, preferably in
the format of a "find" call or the s-exp format used by find-cmd.

What I want to have is an export to these formats so that you can save
the results in these forms.  I guess the reverse should not be too hard.

> In fact, that's about the only advantage I find for such a dialog box.

Another advantage is that it can help you to remember what you have
forgotten.  I for example repeatedly forget that e.g. for

       -ctime n File's status was last changed n*24 hours ago.  See the
              comments for -atime to under‐ stand how rounding affects
              the interpretation of file status change times.

what I want is

       -n     for less than n,

e.g. -ctime -1 for "status changed since last day" but I tend to try
with -ctime 1 and wonder why it fails until I remember that I need "-".
With the widget based version I can force the user to think about the
sign by making it mandatory (with a reasonable default).

> > I think you're looking for the `lazy` widget.
>
> Or maybe just split it up, having part of it use `repeat'?

`lazy' is perfect.  AFAIU `repeat' won't do since the syntax of "find"
is actually recursive, so there is no way to avoid recursive widgets.

Thanks,

Michael.



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

* RE: A widget-based version of find-cmd
  2019-06-03 22:53     ` Michael Heerdegen
@ 2019-06-03 23:28       ` Drew Adams
  2019-06-13 23:35         ` Michael Heerdegen
  0 siblings, 1 reply; 13+ messages in thread
From: Drew Adams @ 2019-06-03 23:28 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Stefan Monnier, emacs-devel

> > One of the advantages of a dialog box in such contexts
> > is setting it and reusing it for multiple search actions
> > (interspersed with other, non-search actions).
> 
> Currently it's only planned to let the buffers stay alive.  I dunno if I
> can save a buffer showing arbitrary widgets?  I guess I would have to
> create the widget view from an internal representation, preferably in
> the format of a "find" call or the s-exp format used by find-cmd.

Keeping the buffer is fine.  That's essentially what
I meant.  A user can access the same buffer later, and
just reuse whatever choices were already filled out.

> What I want to have is an export to these formats so that you can save
> the results in these forms.  I guess the reverse should not be too hard.

I didn't really mean save persistently.  That would be
a plus - could also be useful.  But what I had in mind
was just the fact that the buffer can be kept and reused.

The ability to reuse a whole bunch of settings is an
advantage that is not really available from having
instead completed a whole bunch of inputs.

For completion we have only completion/minibuffer
histories.  And even if someone saves such histories
for possible reuse, the entries are not organized
together, as a coherent set of, say, search attributes.
 
> > In fact, that's about the only advantage I find for such a dialog box.
> 
> Another advantage is that it can help you to remember what you have
> forgotten.  I for example repeatedly forget that e.g. for
> 
>        -ctime n File's status was last changed n*24 hours ago.  See the
>               comments for -atime to under‐ stand how rounding affects
>               the interpretation of file status change times.
> 
> what I want is
> 
>        -n     for less than n,
> 
> e.g. -ctime -1 for "status changed since last day" but I tend to try
> with -ctime 1 and wonder why it fails until I remember that I need "-".
> With the widget based version I can force the user to think about the
> sign by making it mandatory (with a reasonable default).

Yes.  Completion can also do that, but much less conveniently.

> > > I think you're looking for the `lazy` widget.
> >
> > Or maybe just split it up, having part of it use `repeat'?
> 
> `lazy' is perfect.  AFAIU `repeat' won't do since the syntax of "find"
> is actually recursive, so there is no way to avoid recursive widgets.

OK; makes sense.



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

* Re: A widget-based version of find-cmd
  2019-06-03 23:28       ` Drew Adams
@ 2019-06-13 23:35         ` Michael Heerdegen
  2019-09-05 15:04           ` Michael Heerdegen
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Heerdegen @ 2019-06-13 23:35 UTC (permalink / raw)
  To: Drew Adams; +Cc: Stefan Monnier, emacs-devel

Ok,

attached is the draft/prototype.  I made it a separate file since
overlaps with find-cmd.el are so small.  Main thing left to do is to add
the help texts and commentaries.

Open questions/ to discuss further:

(1) For the find option query I needed to hack into the editable-list
widget definition.  Would be good if this would be possible out of the
box.

I guess I have to implement the selection dialog completely myself.  I
want a query to select an item from a list.  Items have annotations, and
are in categories.  Items should be choosable by using the categories,
but not necessarily (if I know I want "name", I don't want to get all
the assistance stuff in the way).  AFAIK there is nothing predefined I
could use, right?  I need it as minibuffer completion version and as
popup menu.

(2) What would also be good would be an upgraded widget that is (i)
foldable and, even better (ii) movable with drag and drop to be able to
reorder given "find" options without the need to start from the
beginning.

What already worked out of the box (to my surprise) was to insert items
in between in editable-list.  I guess the drag-and-drop thing would't be
too hard to do (just need to delete the widget and recreate a copy at
the drop point).

(3) I don't see any obvious/natural way to make the find call become
part of some history.  I guess it could be nice if

  (find-dired dir (find-cmd FIND-CMD-S-EXP ...))

would become part of the history of M-: or so.

Ok, here is the file - remember: prototype.

#+begin_src emacs-lisp
;;; find-cmd-widget.el --- Build a valid find(1) command with widgets -*- lexical-binding: t -*-

;; Copyright (C) 2019 Free Software Foundation, Inc

;; Author: Michael Heerdegen <michael_heerdegen@web.de>
;; Maintainer: Michael Heerdegen <michael_heerdegen@web.de>
;; Created: 10 Jun 2019
;; Keywords: convenience
;; Compatibility: GNU Emacs 26
;; Version: 0.1
;; Package-Requires: ((emacs "26"))


;; This file is not part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; ...

;;; Code:

;;;; Requirements

(require 'widget)
(require 'find-cmd)
(require 'subr-x)
(require 'cus-edit)
(eval-when-compile (require 'wid-edit))

;;;; The other stuff

(defvar find-cmd-widget-find-arg-alist
  '((and find-and "combiners")
    (not find-not "combiners")
    (or  find-or  "combiners")

    (a find-and   "combiners")
    (n find-not   "combiners")
    (o find-or    "combiners")

    (prune find-prune "combiners")

    ;; switches
    (L (0) "switches")
    (P (0) "switches")
    (H (0) "switches")

    ;; generic tests
    (amin       (1)   "generic tests")
    (anewer     (1)   "generic tests")
    (atime      (1)   "generic tests")
    (cmin       (1)   "generic tests")
    (cnewer     (1)   "generic tests")
    (ctime      (1)   "generic tests")
    (empty      (0)   "generic tests")
    (executable (0)   "generic tests")
    (false      (0)   "generic tests")
    (fstype     (1)   "generic tests")
    (gid        (1)   "generic tests")
    (group      (1)   "generic tests")
    (ilname     (1)   "generic tests")
    (iname      (1)   "generic tests")
    (inum       (1)   "generic tests")
    (ipath      (1)   "generic tests")
    (iregex     (1)   "generic tests")
    (iwholename (1)   "generic tests")
    (links      (1)   "generic tests")
    (lname      (1)   "generic tests")
    (mmin       (1)   "generic tests")
    (mtime      (1)   "generic tests")
    (name       (1)   "generic tests"  nil "shell glob pattern; needs to match the complete name")
    (newer      (1)   "generic tests")
    (nogroup    (0)   "generic tests")
    (nouser     (0)   "generic tests")
    (path       (1)   "generic tests")
    (perm       (0)   "generic tests")
    (readable   (0)   "generic tests")
    (regex      (1)   "generic tests")
    (samefile   (1)   "generic tests")
    (size       (1)   "generic tests")
    (true       (0)   "generic tests")
    (type       (1)   "generic tests")
    (uid        (1)   "generic tests")
    (used       (1)   "generic tests")
    (user       (1)   "generic tests")
    (wholename  (1)   "generic tests")
    (writable   (0)   "generic tests")
    (xtype      (nil) "generic tests")

    ;; normal options (always true)
    (daystart              (0) "normal options (always true)")
    (depth                 (0) "normal options (always true)")
    (maxdepth              (1) "normal options (always true)")
    (mindepth              (1) "normal options (always true)")
    (mount                 (0) "normal options (always true)")
    (noleaf                (0) "normal options (always true)")
    (ignore_readdir_race   (0) "normal options (always true)")
    (noignore_readdir_race (0) "normal options (always true)")
    (regextype             (1) "normal options (always true)")
    (xdev                  (0) "normal options (always true)")

    ;; actions
    (delete  (0) "actions")
    (print0  (0) "actions")
    (printf  (1) "actions")
    (fprintf (2) "actions")
    (print   (0) "actions")
    (fprint0 (1) "actions")
    (fprint  (1) "actions")
    (ls      (0) "actions")
    (fls     (1) "actions")
    (prune   (0) "actions")
    (quit    (0) "actions")

    ;; these need to be terminated with a ;
    (exec    (1 find-command t) "these need to be terminated with a ;")
    (ok      (1 find-command t) "these need to be terminated with a ;")
    (execdir (1 find-command t) "these need to be terminated with a ;")
    (okdir   (1 find-command t) "these need to be terminated with a ;"))
  "Doc...")

(defvar-local find-cmd-widget-main-widget nil)
(defvar-local find-cmd-widget-preview-widget-1 nil)
(defvar-local find-cmd-widget-preview-widget-2 nil)

(defun find-cmd-widget-create-find-cmd (sexp)
  `(let ((default-directory ,(car sexp)))
     (find-cmd ,@(cadr sexp))))

(defun find-cmd-widget-create-find-call (sexp)
  (let ((default-directory (car sexp)))
    (apply #'find-cmd (cadr sexp))))

(defalias 'find-cmd-orig-widget-choose (symbol-function 'widget-choose))

(defun find-cmd-widget-menu-choice-action (&rest args)
  (cl-letf (((symbol-function #'widget-choose)
             #'find-cmd-widget--widget-choose))
    (apply #'widget-choice-action args)))

(defun find-cmd-widget--widget-choose (title items &optional event)
  (let ((widget-menu-max-size 100))
    (if event
        ;; mouse click
        (progn
          (x-popup-menu
           event
           (apply #'list title
                  (seq-group-by
                   (lambda (item)
                     (nth 2 (assoc (intern (car item)) find-cmd-widget-find-arg-alist)))
                   items))))
      (find-cmd-orig-widget-choose title (cl-sort items #'string< :key #'car)))))

(define-widget 'find-expr 'lazy
  "Doc..."
  :format "...:\n%v"
  :type
  (cl-flet ((just-true (lambda (_) t))
            (value-get-1 (lambda (command)
                           (lambda (w) (list command (widget-field-value-get w))))))
    `(editable-list
      :args
      ((menu-choice
        :action find-cmd-widget-menu-choice-action
        :args
        ,(append
          (delq nil
                (mapcar
                 (pcase-lambda ((and `(,name ,(or (and (pred listp) `(,arity))
                                                  (let arity nil))
                                             . ,rest)
                                     (let name-string (symbol-name name))
                                     (let hint (nth 2 rest))))
                   (ignore name rest)
                   (and arity
                        (if (zerop arity)
                            `(choice-item :tag ,name-string
                                          :value-get ,(lambda (_w) (list name)))
                          `(editable-field :menu-tag ,name-string
                                           :size 6
                                           :validate ,#'just-true
                                           :format ,(concat
                                                     name-string
                                                     ": %v"
                                                     (and hint
                                                          (format "  (%s)" hint))
                                                     "\n")
                                           :value-get ,(value-get-1 name)
                                           :keymap widget-field-keymap))))
                 find-cmd-widget-find-arg-alist))
          (mapcar
           (lambda (combiner)
             (let ((sname (symbol-name combiner)))
               `(find-expr :tag ,sname
                           :format ,(concat sname "\n%v")
                           :value-inline ,(lambda (w) `((,combiner ,@(widget-child-value-get w)))))))
           '(or and not prune))))))))

(define-widget 'find 'group
  "Doc..."
  :format "%v"
  :notify (lambda (w &rest _)
            (widget-value-set find-cmd-widget-preview-widget-1
                              (string-trim-right
                               (pp-to-string
                                (find-cmd-widget-create-find-cmd (widget-value w)))))
            (widget-value-set find-cmd-widget-preview-widget-2
                              (find-cmd-widget-create-find-call (widget-value w))))
  :args
  `((item :format "find %[path%]: %v\n\n"
          :value ,default-directory
          :action (lambda (w &rest _)
                    (widget-value-set
                     w
                     (read-directory-name "Dir: " (widget-value w)))))
    (find-expr :format "expr:\n%v")))

(defun find-cmd-widget-find-action (&rest _)
  (interactive)
  (async-shell-command (widget-value find-cmd-widget-preview-widget-2)))

(defun find-cmd-widget-find-dired-action (&rest _)
  (interactive)
  (let ((sexp (widget-value find-cmd-widget-main-widget)))
    (find-dired (car sexp)
                (mapconcat #'find-to-string
                           (cadr sexp)
                           ""))))
;;;###autoload
(defun find-cmd-widget ()
  "Doc..."
  (interactive)
  (let ((buf (generate-new-buffer "*Widget Find*")))
    (pop-to-buffer buf)
    (kill-all-local-variables)
    (let ((inhibit-read-only t))
      (erase-buffer))
    (remove-overlays)
    (custom--initialize-widget-variables)
    (setq-local find-cmd-widget-main-widget (widget-create 'find))
    (let ((arrow ?⇩))
      (when (char-displayable-p arrow)
        (insert (propertize (concat "    " (string arrow)) 'face '(:height 2.0)) "\n"))
      (setq-local find-cmd-widget-preview-widget-1
                  (widget-create 'item :value "???"))
      (when (char-displayable-p arrow)
        (insert (propertize (concat "    " (string arrow)) 'face '(:height 2.0)) "\n"))
      (setq-local find-cmd-widget-preview-widget-2
                  (widget-create 'item :value "???")))
    (insert "\n")
    (widget-create 'push-button
                   :tag "find!"
	           :help-echo "Run constructed find command"
                   :action #'find-cmd-widget-find-action)
    (insert "  ")
    (widget-create 'push-button
                   :tag "find-dired!"
	           :help-echo "Run constructed find command as find-dired"
                   :action #'find-cmd-widget-find-dired-action)
    (insert "\n")
    (use-local-map (let ((map (make-sparse-keymap)))
                     (set-keymap-parent map widget-keymap)
                     (define-key map [(control ?c) (control ?c)]
                       #'find-cmd-widget-find-dired-action)
                     map))
    (widget-setup)
    (goto-char (point-min))))

(provide 'find-cmd-widget)
;;; find-cmd-widget.el ends here
#+end_src


Regards,

Michael.



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

* Re: A widget-based version of find-cmd
  2019-06-13 23:35         ` Michael Heerdegen
@ 2019-09-05 15:04           ` Michael Heerdegen
  2019-09-05 17:10             ` Drew Adams
  2019-09-06 12:39             ` local binding ineffective inside widget Stefan Monnier
  0 siblings, 2 replies; 13+ messages in thread
From: Michael Heerdegen @ 2019-09-05 15:04 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier, Drew Adams

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

Hello again,

the nearly feature-complete latest version is attached.  For testing,
just load the file and M-x find-cmd-widget.  The rest should be
self-explanatory.  Some find(1) options need some further fine-tuning.

But I have a question: I want that C-c C-c in the _whole_ pop-up buffer
starts the search - even when point is over a widget.  I didn't get that
work.  The local map is ignored inside widgets.  I don't want to change
all individual widget maps.  There are `widget-keymap' and
`widget-global-map', but using them only works if I modify the global
binding of these variables.  In case of `widget-global-map' this would
even mean changing global-map!  Binding these variables buffer-locally
doesn't have an effect.  Any ideas how to get what I want?

TIA,

Michael.


[-- Attachment #2: find-cmd-widget.el --]
[-- Type: application/emacs-lisp, Size: 31357 bytes --]

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

* RE: A widget-based version of find-cmd
  2019-09-05 15:04           ` Michael Heerdegen
@ 2019-09-05 17:10             ` Drew Adams
  2019-09-05 21:26               ` Michael Heerdegen
  2019-09-06 12:39             ` local binding ineffective inside widget Stefan Monnier
  1 sibling, 1 reply; 13+ messages in thread
From: Drew Adams @ 2019-09-05 17:10 UTC (permalink / raw)
  To: Michael Heerdegen, emacs-devel; +Cc: Stefan Monnier

> the nearly feature-complete latest version is attached.  For testing,
> just load the file and M-x find-cmd-widget.  The rest should be
> self-explanatory.  Some find(1) options need some further fine-tuning.
> 
> But I have a question: I want that C-c C-c in the _whole_ pop-up buffer
> starts the search - even when point is over a widget.  I didn't get that
> work.  The local map is ignored inside widgets.  I don't want to change
> all individual widget maps.  There are `widget-keymap' and
> `widget-global-map', but using them only works if I modify the global
> binding of these variables.  In case of `widget-global-map' this would
> even mean changing global-map!  Binding these variables buffer-locally
> doesn't have an effect.  Any ideas how to get what I want?

Good stuff!

I don't have an answer for `C-c C-c` when point
is on a widget (e.g. in an editable field).
Are you sure you want/need that?



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

* Re: A widget-based version of find-cmd
  2019-09-05 17:10             ` Drew Adams
@ 2019-09-05 21:26               ` Michael Heerdegen
  0 siblings, 0 replies; 13+ messages in thread
From: Michael Heerdegen @ 2019-09-05 21:26 UTC (permalink / raw)
  To: Drew Adams; +Cc: Stefan Monnier, emacs-devel

Drew Adams <drew.adams@oracle.com> writes:

> I don't have an answer for `C-c C-c` when point
> is on a widget (e.g. in an editable field).
> Are you sure you want/need that?

Yes.  I want this package to be useful on a regular basis (not only for
learning), and being able to hit a key instead of needing to move to a
button to start "find" is very convenient -- but only if you don't have
to move out of widgets before.  And in a widget is typically where you
are after finishing constructing your find call.

Michael.



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

* local binding ineffective inside widget
  2019-09-05 15:04           ` Michael Heerdegen
  2019-09-05 17:10             ` Drew Adams
@ 2019-09-06 12:39             ` Stefan Monnier
  2019-09-06 14:10               ` Michael Heerdegen
  1 sibling, 1 reply; 13+ messages in thread
From: Stefan Monnier @ 2019-09-06 12:39 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Drew Adams, emacs-devel

> But I have a question: I want that C-c C-c in the _whole_ pop-up buffer
> starts the search - even when point is over a widget.  I didn't get that
> work.  The local map is ignored inside widgets.

I don't have time to look more closely, but I'd suspect it might be
because the widget uses the `local-map` property instead of the
`keymap` property.  If so, maybe you can change the widget to use the
`keymap` property instead or to dynamically build a keymap that inherits
from the buffer-wide local-map?

A possible workaround is to put the binding inside an ad-hoc minor-mode.


        Stefan




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

* Re: local binding ineffective inside widget
  2019-09-06 12:39             ` local binding ineffective inside widget Stefan Monnier
@ 2019-09-06 14:10               ` Michael Heerdegen
  2019-09-24  9:28                 ` Michael Heerdegen
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Heerdegen @ 2019-09-06 14:10 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Drew Adams, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> [...] I'd suspect it might be because the widget uses the `local-map`
> property instead of the `keymap` property.

That seems to be the case, yes.

> A possible workaround is to put the binding inside an ad-hoc
> minor-mode.

That solution is ok for me, and it works, so I'll just do that.  Thanks!

Michael.



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

* Re: local binding ineffective inside widget
  2019-09-06 14:10               ` Michael Heerdegen
@ 2019-09-24  9:28                 ` Michael Heerdegen
  0 siblings, 0 replies; 13+ messages in thread
From: Michael Heerdegen @ 2019-09-24  9:28 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Drew Adams, emacs-devel

Michael Heerdegen <michael_heerdegen@web.de> writes:

> That solution is ok for me, and it works, so I'll just do that.
> Thanks!

Ok, this also seems to be a bit tricky: find(1) has options -newerXY,
for each combination of X, Y in {a, B, c, m, t} there exists an
according -newerXY option (e.g. -newerBa -- some combinations are not
allowed).  I want to make it so that the user selects literal "-newerXY"
(i.e. there is only one widget for the whole set) and the widget will
prompt for X and Y itself.  And the argument REFERENCE of the option.

Here is the problem: REFERENCE is a file in nearly all cases, but not if
a "t" has been specified.  Then the widget would have to replace the
"file: " child widget with a different kind of "time: " widget, because
in this case the argument will be interpreted as a time.  How can I
implement that?  Do I have to do it by hand, as e.g. in
`widget-delete-button-action' -- or is there a built in solution (then I
didn't find it) to replace child widgets?

TIA, Michael.



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

end of thread, other threads:[~2019-09-24  9:28 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-31  2:15 A widget-based version of find-cmd Michael Heerdegen
2019-06-03 19:07 ` Stefan Monnier
2019-06-03 20:41   ` Drew Adams
2019-06-03 22:53     ` Michael Heerdegen
2019-06-03 23:28       ` Drew Adams
2019-06-13 23:35         ` Michael Heerdegen
2019-09-05 15:04           ` Michael Heerdegen
2019-09-05 17:10             ` Drew Adams
2019-09-05 21:26               ` Michael Heerdegen
2019-09-06 12:39             ` local binding ineffective inside widget Stefan Monnier
2019-09-06 14:10               ` Michael Heerdegen
2019-09-24  9:28                 ` Michael Heerdegen
2019-06-03 22:40   ` A widget-based version of find-cmd Michael Heerdegen

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

	https://git.savannah.gnu.org/cgit/emacs.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).