help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Wizardry Inc.: find-command


From: Emanuel Berg
Subject: Wizardry Inc.: find-command
Date: Mon, 14 Dec 2015 01:50:32 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.4 (gnu/linux)

As is known, today is the 14th. By implication,
yesterday was the 13th. That day is traditionally -
and truthfully - associated with which-craft and
sorcery. Black magic to corrupt pure souls. And not
just their souls. I also refer to their pale, and
perfectly preserved bod - but now I digress. Here is
all the wizardry that can be mustered in one cauldron.
With some luck, those selfsame witches will still
haunt my dreams in gratitude. But 'nuff said: no gods
like worshippers, who praise their fortune before it
is in the sack (pillow). Beware!

;;; find-command --- find the source of the command-at-point DWIM-style
;;;
;;; Commentary:
;;;
;;; This file:
;;;
;;;     http://user.it.uu.se/~embe8573/conf/emacs-init/ide/find-command.el
;;;
;;; Evaluate this to go to the install instructions:
;;;
;;;     (progn (search-forward "How to get it to work:") (recenter 0))
;;;
;;; When programming, this is a common
;;; process/situation:
;;;
;;;   i)  In order have modular, well-organized and
;;;       manageable code, one splits the code up into
;;;       several files based on some
;;;       common denominator.
;;;
;;;  ii)  But do that every day, one ends up with
;;;       hundreds of files in squiggly
;;;       nested directories.
;;;
;;; iii)  Because all code gets tangled up and
;;;       interdependent, which is a good thing, a bad
;;;       thing nevertheless is that working with such
;;;       code implies jumping between code files
;;;       constantly looking for some function that is
;;;       used from some other function, in another
;;;       file, in order to find out what is going on.
;;;
;;; There are many creative ways to navigate between
;;; *files* (i.e., not individual function
;;; definitions). Here is what I use for Emacs and
;;; zsh:
;;;
;;;     http://user.it.uu.se/~embe8573/conf/emacs-init/navigate-fs-keys.el
;;;     http://user.it.uu.se/~embe8573/conf/.zsh/navigate-fs
;;;
;;; As you see, paths and commands are setup
;;; explicitly, which isn't necessarily bad. However,
;;; this program attempts something more ambitious:
;;;
;;;   1) Instead of (only) jumping between *files*,
;;;      the program should jump to the file (if
;;;      necessary) *and*, in particular, it should
;;;      find the sought-after function definition.
;;;
;;;   2) Also, there shouldn't be any metadata -
;;;      neither setup manually as with "navigate-fs",
;;;      nor automatically generated metadata (which
;;;      is another common way to tackle this problem
;;;      by the way). The program should *only* use
;;;      the source, just as Luke - realistically -
;;;      only used the force when he blew up the
;;;      Death Star.
;;;
;;;   3) The program should do this (find a function
;;;      definition) transparently of mode,
;;;      do-what-I-mean style. If the source is Elisp,
;;;      and the function is `lore-and-legend', it
;;;      shouldn't take you to a zsh function tho it
;;;      might share the name of lore and legend.
;;;
;;;   4) The interface should be ultra-fast, involving
;;;      a minimal of short, close keystrokes.
;;;
;;;      One way to use it should be to position point
;;;      at the start of a function name, hit
;;;      a keystroke, and the program should take you
;;;      wherever you need to go.
;;;
;;;      Another way should be: hit a mode-specific
;;;      keystroke and type the function name.
;;;
;;;      (The actual shortcuts are left to the user to
;;;      define. Let's just say, without them, this
;;;      package isn't half as fun. Or good.
;;;      For example, the author has `C-o f' for
;;;      `find-command-dwim' and `C-o z' for
;;;      `find-command-zsh'.)
;;;
;;; How to get it to work:
;;;
;;;   a) For the `thing-at-point' interface to work, you
;;;      need the function `get-search-string' from:
;;;
;;;          http://user.it.uu.se/~embe8573/conf/emacs-init/get-search-string.el
;;;
;;;   b) For the `find-command-zsh' to work, you need:
;;;
;;;          http://user.it.uu.se/~embe8573/conf/.zsh/find-command
;;;
;;;      The environmental variable COMMAND_FILE must
;;;      be set; with zsh, for Emacs to see it, set it
;;;      in ~/.zshenv, e.g.
;;;
;;;          export COMMAND_FILE=~/.some-file
;;;
;;; Bugs, issues, misnomers, possible confusion...
;;;
;;;      - For the program to work with the Emacs
;;;        source (i.e., not only the user's init file
;;;        defuns), the Emacs source must be obtained.
;;;        On a Debian system and Emacs 24, the code
;;;        is in the package emacs24-el. But getting
;;;        it isn't enough; one needs also unpack its
;;;        contents - every file, from x.el.gz into
;;;        plain x.el. Again on a Debian system and
;;;        Emacs 24, this can be done in
;;;        /usr/share/emacs/24.4/lisp on all .gz
;;;        files recursively.
;;;
;;;      - The word "command" in `find-command-elisp'
;;;        is not in the Emacs sense (i.e.,
;;;        interactive functions only) -
;;;        non-interactive functions can be found as
;;;        well with this tool.
;;;
;;;      - For the program to work, one has to write
;;;        the target code so that the regexps will
;;;        match it. The author simply made it work
;;;        the way he writes it in (so far) zsh and
;;;        Elisp, neither ways are radical in any way.
;;;        Because there is no parsing here; only
;;;        regexps are at work. The user might as well
;;;        consider this as motivation to use clear
;;;        style when coding. :)
;;;
;;; Code:

(require 'cl-macs)

(require 'get-search-string) ; don't have this? evaluate me: (goto-line 86)

(defun file-to-string (file)
  "Put the contents of FILE into a string and return it."
  (interactive "Ffile: ")
  (with-temp-buffer
    (insert-file-contents file)
    (buffer-string) ))

(defun shell-command-silent (command)
  "Execute a shell COMMAND with no output to the echo-area."
  (process-file shell-file-name
                nil ; INFILE
                nil ; BUFFER
                nil ; DISPLAY
                shell-command-switch command) )

(defun find-command-dwim ()
  "Find the command at point, or, if none, prompt the user.
The current `major-mode' determines where to look for the command."
  (interactive)
  (cl-case major-mode
    (sh-mode          (find-command-zsh))
    (emacs-lisp-mode  (find-command-elisp))
    (t                (message "`%s' does not compute - DIY, man!" major-mode)) 
))
(defalias 'find-command 'find-command-dwim)

(defun beginning-of-line-at-top ()
  "Position point at the `beginning-of-line'.
Then put that line at the top of the window."
  (beginning-of-line)
  (recenter 0) )

(defun find-command-elisp (&optional command)
  "Find the source for an Emacs Lisp COMMAND.
Actually anything that can be found with `find-lisp-object-file-name' is OK."
  (interactive)
  (let*((cmd (intern (or command (get-search-string "Elisp command"))))
        (file (find-lisp-object-file-name cmd (symbol-function cmd))) )
    (when file
      (find-file file)
      (goto-char (point-min))
      (when (search-forward-regexp (format "defun %s " cmd) (point-max) t) ; 
NOERROR
        (beginning-of-line-at-top) ))))

;; This command uses 'find-zsh-command' in:
;;   ~/.zsh/find-command
;;   http://user.it.uu.se/~embe8573/conf/.zsh/find-command
;; COMMAND_FILE is set in:
;;   ~/.zshenv
;;   http://user.it.uu.se/~embe8573/conf/.zshenv
(defun find-command-zsh (&optional command)
  "Find the source for a zsh COMMAND.
This requires an external zsh script to work."
  (interactive)
  (let*((cmd                 (or command (get-search-string "zsh command")))
        (search-command      (format "find-zsh-command %s" cmd))
        (file-data-path      (getenv "COMMAND_FILE"))
        (erase-data-command  (format "echo -n > %s" file-data-path)) )
    (shell-command-silent erase-data-command)
    (shell-command-silent search-command)
    (message search-command)
    (let ((file               (file-to-string file-data-path))
          (case-fold-search   nil) ; i.e., case sensitive search
          (cmd-search-string  (format "%s ()" cmd)) )
      (unless (string= file "")
        (find-file file)
        (goto-char (point-min))
        (when (search-forward-regexp cmd-search-string (point-max) t) ; NOERROR
          (beginning-of-line-at-top) )))))

;; test:
;;
;;   (find-command-elisp "find-command-dwim")
;;   (find-command-elisp "no-command")
;;
;;   (find-command-zsh "find-zsh-command")
;;   (find-command-zsh "no-command")

(provide 'find-command)

;;; find-command.el ends here

-- 
underground experts united
http://user.it.uu.se/~embe8573




reply via email to

[Prev in Thread] Current Thread [Next in Thread]