2

I've recently started using function apropos-value and have found its output burdensome-ly long, mainly due to a limited number of huge variables that I knew in advance would contain the value I was looking for, but which were not of interest to me.

Is there any way to limit the scope of function apropos-value, so that it not search certain variables?

In my case, I know in advance that the value will appear in variables such as kill-ring, values, minibuffer-history, and I have learned the hard way that taking a "hacktivist shortcut" such as (setq kill-ring nil) messes up future ability to use the kill ring.

  • You could try creating an interactive version of the command that lets you first select a subset of the variables using helm it another incremental completion framework. – Qudit Apr 3 '18 at 16:58
3

You can try to modify the function apropos-value-internal, which is used by apropos-value. For example,

(define-advice apropos-value-internal
    (:around (old-fun predicate symbol function) ignore)
  "Ignore some variables for `apropos-value'."
  (unless (memq symbol '(kill-ring values minibuffer-history))
    (funcall old-fun predicate symbol function)))

However, if you think such feature might be also userful for others, you should consider reporting a bug (feature request) via M-x report-emacs-bug.

  • I tried your approach, and while it would work for a simple change to apropos-value, I couldn't get it to work for the kind of change I envisioned. See my answer for what I had in mind. – user1404316 Apr 5 '18 at 14:52
2

UPDATED 2018-04-07: "circular structure" issue resolved (explained in paragraph 4).

UPDATED 2018-04-07: A bug with obarray usage was fixed. See paragraph 7.

  1. Below is a replacement for the stock emacs apropos-value function that I think will meet my needs.

  2. User xuchunyang's answer would work for a basic change to apropos-value, and I did experiment with it, but it didn't seem like the correct tool for dealing with how I wanted universal prefix arguments to control how the function would operate.

  3. User Drew's answer looks like it would work, but I was intimidated from even trying it because it seems overwhelming. Thanks Drew for pointing out the icicles package - I intend to give it a "test drive" at some point, but not for a simple operation such as this.

  4. The code below had originally for me generated an error "Apparently circular structure being printed" (possibly because of this). This was eventually resolved when restarting emacs! The error message may have been issued due to some memory management detail, because what caused me to restart emacs was a "memory exhausted" warning stubbornly ignored...

  5. As of now (2018-04-08), the code works. Please let me know if you experience a problem with it. My intent is to add another feature to it, and to propose it as a patch to the emacs developers. The additional feature that I have in mind is a boolean variable apropos-value-limited-print to print only symbol names, not their content, in order to greatly reduce the size of the output buffer ( A user can always interrogate values with C-h v when point is on the symbol name).

  6. I'll wait a few days for feedback before marking this (my own) answer as accepted.

  7. I found and fixed a bug in how I was trying to create an obarray: "Unlike Common Lisp, Emacs Lisp does not provide for interning a single symbol in several obarrays"

    (defcustom apropos-value-exclude-list
      '(kill-ring values minibuffer-history buffer-name-history
         command-history ivy--all-candidates)
    "List of variable names to be excluded from `apropos-value' searches" 
      :type '(repeat variable))
    
    
    (defun my-apropos-value (pattern &optional do-all)
      "Allow `apropos-value' to limit scope of its searches.
    
    With \\[universal-argument] prefix, or if `apropos-do-all' is
    non-nil, also looks at function definitions (arguments,
    documentation and body) and at the names and values of
    properties.
    
    With two \\[universal-argument] prefixes, excludes the variables
    listed in `apropos-value-exclude-list' from its search.
    
    With three \\[universal-argument] prefixes, performs a search
    only on the variables listed in `apropos-value-exclude-list'."
      (interactive (list (apropos-read-pattern "value")
                 current-prefix-arg))
      (apropos-parse-pattern pattern)
      (or do-all (when apropos-do-all (setq do-all '(4))))
      (setq apropos-accumulator ())
      (let (f v p)
        (if (equal do-all '(64)) ; C-u C-u C-u
          (dolist (symbol apropos-value-exclude-list)
            (when (setq v (apropos-value-internal 'boundp symbol 'symbol-value))
              (setq apropos-accumulator
                (cons (list symbol (apropos-score-str v) nil v nil) apropos-accumulator))))
         (mapatoms (lambda (symbol)
           (setq f nil v nil p nil)
           (or (memq symbol '(apropos-regexp
                   apropos-pattern apropos-all-words-regexp
                   apropos-words apropos-all-words
                   do-all apropos-accumulator apropos-value-exclude-list
                   symbol f v p))
               (and (equal do-all '(16)) ; C-u C-u
                    (memq symbol apropos-value-exclude-list))
               (setq v (apropos-value-internal 'boundp symbol 'symbol-value)))
           (when (equal do-all '(4)) ; C-u
             (setq f (apropos-value-internal 'fboundp symbol 'symbol-function)
                   p (apropos-format-plist symbol "\n    " t)))
           (if (apropos-false-hit-str v)
               (setq v nil))
           (if (apropos-false-hit-str f)
               (setq f nil))
           (if (apropos-false-hit-str p)
               (setq p nil))
           (if (or f v p)
               (setq apropos-accumulator (cons (list symbol
                              (+ (apropos-score-str f)
                                 (apropos-score-str v)
                                 (apropos-score-str p))
                              f v p)
                            apropos-accumulator)))))))
      (let ((apropos-multi-type (if (equal do-all '(4)) t nil)))
        (apropos-print nil "\n----------------\n")))
    
1

If you use use Icicles then you can use multi-command icicle-apropos-value.

With a prefix arg you can limit the effect to only variables, functions, faces, plists, etc.

You can match not only the value but also the function/variable etc. name, if you wish (multi-completion). So you can easily exclude certain variables (by name) from consideration.

More importantly, you can refine matches incrementally using progressive completion. And that includes being able to exclude matches (chip away the non-elephant).

icicle-apropos-value is an interactive compiled Lisp function in icicles-cmd1.el.

It is bound to menu-bar help-menu apropos icicles icicle-apropos-value, menu-bar help-menu apropos apropos-var-value, menu-bar help-menu search-documentation find-option-by-value.

(icicle-apropos-value)

Choose a variable, function, or other symbol description. This is similar to vanilla command apropos-value, but you can match against the variable name and its printed value at the same time.

By default, each completion candidate is a multi-completion composed of a variable name plus its value. They are separated by icicle-list-join-string ("^G^J", by default).

With a prefix arg, candidates are different kinds of symbols:

  • < 0: functions and their defs (but byte-compiled defs are skipped)

  • > 0: symbols and their plists

  • = 0: variables and their values, functions and their definitions, and other symbols and their plists

  • plain (C-u): use the last-computed (cached) set of candidates

You can use C-$ during completion to toggle filtering the domain of initial candidates according to the prefix argument, as follows:

  • none: only user options (+ values)
  • < 0: only commands (+ definitions)
  • > 0: only faces (+ plists)
  • = 0: only options (+ values), commands (+ defs), faces (+ plists)

See also:

  • icicle-apropos-vars-w-val-satisfying, icicle-describe-vars-w-val-satisfying - values satisfy a predicate
  • icicle-plist - similar to this command with positive prefix arg
  • icicle-vardoc, icicle-fundoc, icicle-doc - match name & doc
  • icicle-apropos-options-of-type, icicle-describe-option-of-type - match name & defcustom type

Because you will often use this command in contexts that result in many, many completion candidates, the following are turned off by default for this command:

  • Icomplete mode. You can toggle this using M-i M-#.
  • Icicles incremental completion. You can cycle this using M-i #.

Read input, then call icicle-doc-action to act on it.

Input-candidate completion and cycling are available. While cycling, these keys with prefix C- are active:

  • C-mouse-2, C-return - Act on current completion candidate only
  • C-down, C-wheel-down - Move to next completion candidate and act
  • C-up, C-wheel-up - Move to previous completion candidate and act
  • C-next - Move to next apropos-completion candidate and act
  • C-prior - Move to previous apropos-completion candidate and act
  • C-end - Move to next prefix-completion candidate and act
  • C-home - Move to previous prefix-completion candidate and act
  • C-! - Act on all candidates, successively (careful!)

When candidate action and cycling are combined (e.g. C-next), user option icicle-act-before-cycle-flag determines which occurs first.

With prefix C-M- instead of C-, the same keys (C-M-mouse-2, C-M-RET, C-M-down, and so on) provide help about candidates.

Use mouse-2, RET, or S-RET to finally choose a candidate, or C-g to quit.

This is an Icicles command - see command icicle-mode.

  • I up-voted this answer because it points out what seems to be an excellent package for emacs, but it also seems overwhelming for a solution to a single problem, and I was intimidated from trying it. I do intend at some point to give icicles a "test drive". – user1404316 Apr 5 '18 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.