Is there a function included with Emacs to recursively walk the directory structure and call a function? - emacs

I would like to recursively walk down the directory structure from a particular point and call copyright-update-directory at each level.
Is there a function included with Emacs 24 that would help with this? For example something like:
(recursive-directory-walk "~/src/foo" '(copyright-update-directory))
If no such function exists, some pointers on getting started implementing this (or a working implementation) would be great.

The f.el library (github) on MELPA contains functions for filesystem traversal.
(mapc 'copyright-update-directory (f-directories "~/path" nil t))
This will descend the directory hierarchy recursively. See the documentation for f-directories.

Not sure if exists, but not very hard to write your own.
(defun folder-dirs (folder)
(delete-if-not 'file-directory-p
(mapcar (lambda(arg) (file-name-as-directory (concat (file-name-as-directory folder) arg)))
(delete-if (lambda (arg) (or (string= ".." arg) (string= "." arg)))
(directory-files folder)))))
(defun recursively-run-on-every-dir (fn folder)
"FN - function, taking one argument;
FOLDER - initial forder"
(funcall fn folder)
(mapc (lambda(arg) (recursively-run-on-every-dir fn arg))
(folder-dirs folder))
nil)
;; use your function instead of print
(recursively-run-on-every-dir 'print "/your/initial/path/")

Just use find-lisp
(require 'find-lisp)
;; a simple function, just to test
(defun my-funct (x)
(princ x)
(terpri))
(mapc 'my-funct (find-lisp-find-files "~/src/foo/" "\\.txt$"))

Emacs has the build-in function directory-files-recursively for this purpose:
(mapc #'YOUR-FUNCTION
(remove-if-not
#'file-directory-p ;only dirs
(directory-files-recursively YOUR-DIRECTORY "" t)))
It's also much faster than the f-directories function mentioned in the other answer because it doesn't use recursion internal.

I think Chris Barrett's answer is the correct and idiomatic one. However, for learning purposes i wanted to implement Python's os.walk, a general function for breadth-first traversing of directory trees. I used dash.el list library and f.el file and directory libraries. This is a stack-based implementation translated from Python.
(defun walk (path)
(let ((stack (list (f-full path)))
result)
(while stack
(let* ((path (pop stack))
(ds_ (f-directories path))
(ds (-map 'f-relative ds_))
(fs (-map 'f-relative (f-files path))))
(--each ds_ (!cons it stack))
(!cons (list path ds fs) result)))
(reverse result)))
See functions: f-full, pop, f-directories, f-relative, f-files, --each, !cons, reverse. Now you can use it in loops the same you would use it in Python:
(loop for (b ds fs) in (walk path)
do (copyright-update-directory b "*"))

Related

How to make eshell-autojump case insensitive under Linux

Under Linux, eshell-autojump will do case sensitive matching which I just find a nuisance. I've tried to circumvent this by advising eshell/j with a eshell-under-windows-p that always returns t but to my chagrin eshell-under-windows-p invoked in eshell/j is unaffected by cl-letf. I've modified my eshell/j a bit to give me some debug info:
;; Modified eshell/j inside eshell-autojump.el to this
(defun eshell/j (&rest args) ; all but first ignored
"Jump to a directory you often cd to.
This compares the argument with the list of directories you usually jump to.
Without an argument, list the ten most common directories.
With a positive integer argument, list the n most common directories.
Otherwise, call `eshell/cd' with the result."
(setq args (eshell-flatten-list args))
(let ((path (car args))
(candidates (eshell-autojump-candidates))
(case-fold-search (eshell-under-windows-p))
result)
(when (not path)
(setq path 10))
(message "case-fold-search = %S" case-fold-search)
(message "eshell-under-windows-p returns %s from inside eshell/j" (eshell-under-windows-p))
(if (and (integerp path) (> path 0))
(progn
(let ((n (nthcdr (1- path) candidates)))
(when n
(setcdr n nil)))
(eshell-lisp-command (mapconcat 'identity candidates "\n")))
(while (and candidates (not result))
(if (string-match path (car candidates))
(setq result (car candidates))
(setq candidates (cdr candidates))))
(eshell/cd result))))
My init.el adds the advice to attempt to make eshell/j caseless by trying to trick it to think we are on Windows:
;; Added to init.el
(require 'eshell-autojump)
(advice-add 'eshell/j :around
(lambda (orig-fun &rest xs)
(cl-letf (((symbol-function 'eshell-under-windows-p) (lambda () t)))
(progn (message "eshell-under-windows-p returns %s from lambda" (eshell-under-windows-p)) (apply orig-fun xs)))))
But all I get in Messages buffer when I try to jump in eshell is:
;; I get in *Messages*
eshell-under-windows-p returns t from lambda
case-fold-search = nil
eshell-under-windows-p returns nil from inside eshell/j
My rookie knowledge of elisp is not enough to wrestle with probable scoping issues here. Can anyone decode why eshell-under-window-p is unaffected when called from eshell/j here?
I've found the answer. cl-letf does not work for byte compiled functions. As eshell-autojump is a package it gets byte compiled upon installation and cl-letf cannot be used to modify it's internal behavior. I had to resort to redefining the eshell/j which is a suboptimal solution.

Is there any way to see the implementations of built-in macros in Common Lisp?

Common Lisp built-in functions are probably implemented in C. But I imagine macros are implemented in lisp (sorry if I'm wrong about any of two sentences). Is there any way (through some function or some macro) to see the implementations of built-in macros in Common Lisp? I'm using CLisp.
The ability to inspect function and macro definitions is a feature of your development environment. These days it is typical to use SLIME or SLY with emacs as the basis of a Lisp development environment. I personally use SLIME, but I have heard good things about SLY, too.
In SLIME you can invoke slime-edit-definition (either by keying M-x slime-edit-definition or by using the keybinding M-.) to visit a definition for the symbol under the cursor in a source file. This works both when editing in a source file, or from the REPL. This feature is extremely useful when you want to inspect some library code you are working with, but you can also view a lot of built-in definitions this way. You can even jump to a new definition from a new symbol found in whatever definition you are currently inspecting.
After you are done looking at a definition, you can use M-x slime-pop-find-definition-stack, or the easier to remember keybinding M-, (M-* will also work), to back out through the previously viewed definitions, eventually returning to your starting point.
Here is an example, in SBCL:
CL-USER> with-open-file[press M-.]
(Note that the "[press M-.]" above is not typed, but only meant to remind what action is taken here). With the cursor on or right after the symbol with-open-file, press M-. to see the definition:
(sb-xc:defmacro with-open-file ((stream filespec &rest options)
&body body)
(multiple-value-bind (forms decls) (parse-body body nil)
(let ((abortp (gensym)))
`(let ((,stream (open ,filespec ,#options))
(,abortp t))
,#decls
(unwind-protect
(multiple-value-prog1
(progn ,#forms)
(setq ,abortp nil))
(when ,stream
(close ,stream :abort ,abortp)))))))
This time after keying M-. SLIME gives a choice of definitions to view:
CL-USER> and[press M-.]
Displayed in an emacs buffer:
/path-to-source/sbcl-2.0.4/src/code/macros.lisp
(DEFMACRO AND)
/path-to-source/sbcl-2.0.4/src/pcl/ctypes.lisp
(DEFINE-METHOD-COMBINATION AND)
We want to see the macro definition, so move the cursor to the line showing (DEFMACRO AND), and the following definition is displayed:
;; AND and OR are defined in terms of IF.
(sb-xc:defmacro and (&rest forms)
(named-let expand-forms ((nested nil) (forms forms) (ignore-last nil))
(cond ((endp forms) t)
((endp (rest forms))
(let ((car (car forms)))
(cond (nested
car)
(t
;; Preserve non-toplevelness of the form!
`(the t ,car)))))
((and ignore-last
(endp (cddr forms)))
(car forms))
;; Better code that way, since the result will only have two
;; values, NIL or the last form, and the precedeing tests
;; will only be used for jumps
((and (not nested) (cddr forms))
`(if ,(expand-forms t forms t)
,#(last forms)))
(t
`(if ,(first forms)
,(expand-forms t (rest forms) ignore-last))))))
There is more stuff here, since you are now actually in the source file that contains the definition for and; if you scroll down a bit you can also find the definition for or.
A lot of SBCL functions are written in Lisp; SBCL has a very high-quality compiler, so a lot of stuff that you might otherwise expect to be written in C can be written in Lisp without loss of performance. Here is the definition for the function list-length:
CL-USER> list-length[press M-.]
(defun list-length (list)
"Return the length of the given List, or Nil if the List is circular."
(do ((n 0 (+ n 2))
(y list (cddr y))
(z list (cdr z)))
(())
(declare (type fixnum n)
(type list y z))
(when (endp y) (return n))
(when (endp (cdr y)) (return (+ n 1)))
(when (and (eq y z) (> n 0)) (return nil))))
The same thing can be done when using CLISP with SLIME. Here is with-open-file as defined in CLISP:
CL-USER> with-open-file[press M-.]
(defmacro with-open-file ((stream &rest options) &body body)
(multiple-value-bind (body-rest declarations) (SYSTEM::PARSE-BODY body)
`(LET ((,stream (OPEN ,#options)))
(DECLARE (READ-ONLY ,stream) ,#declarations)
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1
(PROGN ,#body-rest)
;; Why do we do a first CLOSE invocation inside the protected form?
;; For reliability: Because the stream may be a buffered file stream,
;; therefore (CLOSE ,stream) may produce a disk-full error while
;; writing the last block of the file. In this case, we need to erase
;; the file again, through a (CLOSE ,stream :ABORT T) invocation.
(WHEN ,stream (CLOSE ,stream)))
(WHEN ,stream (CLOSE ,stream :ABORT T))))))
But, many CLISP functions are written in C, and those definitions are not available to inspect in the same way as before:
CL-USER> list-length[press M-.]
No known definition for: list-length (in COMMON-LISP-USER)

Rename function in a specific package on Common Lisp

I want to use the package cl-ppcre and series directly on my common lisp environment. I use sly, so in my slynkrc I add this code:
(setf (cdr (assoc '*print-length* slynk:*slynk-pprint-bindings*)) 20)
(setf *print-length* 20)
(setf *evaluator-mode* :interpret)
(ql:quickload '(:alexandria
:cl-ppcre
:cl-interpol
:series
:cl-actors
:chanl
:lparallel))
(eval-when (:compile-toplevel :execute :load-toplevel)
(series::install))
(defun λ-reader (stream char)
(declare (ignore char stream))
'LAMBDA)
(set-macro-character #\λ #'λ-reader)
(use-package :cl-ppcre)
(use-package :cl-interpol)
(interpol:enable-interpol-syntax)
The problem with this is whith the symbol function split. that is in both packages defined.
#<THREAD "main thread" RUNNING {10005605B3}>:
USE-PACKAGE #<PACKAGE "CL-PPCRE"> causes name-conflicts in
#<PACKAGE "COMMON-LISP-USER"> between the following symbols:
CL-PPCRE:SPLIT, SERIES:SPLIT
See also:
In Scala you can import, Renaming a class, but in this case I can use shadowing import, and import only what I need, what is the best solution for that, and if it is possible to import and rename a function in common lisp
You could maybe do it like this:
(defun alias% (as symbol &key (package *package*))
(when (fboundp symbol)
(setf (symbol-function as) (symbol-function symbol)))
(when (boundp symbol)
(setf (symbol-value as) (symbol-value symbol)))
(setf (symbol-plist as) (symbol-plist symbol))
;; maybe also documentation of all types
(shadowing-import as package))
(defmacro defalias (as symbol &key (package *package*))
`(eval-when (:compile-toplevel :load-toplevel :execute)
(alias% ',as ',symbol :package ,package)))
Then you can do:
(defalias foo cl:list)
(foo 1 2 3) ; => (1 2 3)
Looking at the doc on CLtL2, I'd say there is no macro to do that. Please prove me wrong.
Maybe the following works ? I didn't test properly edit: it doesn't work as is.
(use-package :cl-ppcre)
(setf (fdefinition 're-split) #'split) ;; create an alias
(unintern 'split)
(use-package :series)
And now use re-split and split.

Listing all top level global variables in emacs

Mostly for my own edification I'm trying to list all of the global variables loaded in the current Emacs session. What I was thinking about doing is producing an HTML file with all of the functions listed. Of course, what would also be useful is the file where the function, var, etc was defined.
Is there anything already built into emacs to help?
L-
Something along these lines should do:
(let ((result '()))
(mapatoms (lambda (x)
(when (boundp x)
(let ((file (ignore-errors
(find-lisp-object-file-name x 'defvar))))
(when file
(push (cons x file) result))))))
result)
Warning: it takes a long time to finish.

Unable to add a directory and all its subdirectories to load-path in Emacs

The question is similar to one.
However, it differs in putting all subdirectories achievable in the folder too.
Jouni's code which puts first level folders achievable
(let ((base "~/Projects/emacs"))
(add-to-list 'load-path base)
(dolist (f (directory-files base))
(let ((name (concat base "/" f)))
(when (and (file-directory-p name)
(not (equal f ".."))
(not (equal f ".")))
(add-to-list 'load-path name)))))
How can you put a directory and all its subdirectories to load-path in Emacs?
My answer in the other question does handle multiple levels of subdirectories.
The code for reference
(let* ((my-lisp-dir "~/.elisp/")
(default-directory my-lisp-dir)
(orig-load-path load-path))
(setq load-path (cons my-lisp-dir nil))
(normal-top-level-add-subdirs-to-load-path)
(nconc load-path orig-load-path))
Here's an adaptation of Jouni's answer that uses a helper function that you can tailor.
One advantage of the helper function is that you can trace it when it does something unexpected, because it's a pure function, so doesn't side-effect into your load-path. I tried using the normal-top-level-add-subdirs-to-load-path, but everything in it is so side-effecting and dependent on unpredictable special variables, that it was just easier to write something fresh that was clean. Note that my answer does not use inodes, so may be less efficient.
A second advantage of this approach is that it lets you tailor what files you would like to ignore.
(defun add-to-load-path-with-subdirs (directory &optional endp)
(let ((newdirs (lp-subdir-list directory)))
(if endp (setq load-path (append load-path newdirs))
(setq load-path (nconc newdirs load-path)))))
(defconst +lp-ignore-list+
(list "CVS" ".git" ".svn" ".." "."))
(defun lp-subdir-list (base &optional ignore)
(unless ignore
(setq ignore +lp-ignore-list+))
(let ((pending (list base))
(retval nil))
(while pending
(let ((dir (pop pending)))
(push dir retval)
(dolist (f (directory-files dir))
(let ((name (concat dir "/" f)))
(when (and (not (member f ignore))
(file-directory-p name))
(push name pending)
(push name retval))))))
(reverse retval)))
Simple answer:
(normal-top-level-add-subdirs-to-load-path)