[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
- Wizardry Inc.: find-command,
Emanuel Berg <=