Skip to content

Latest commit

 

History

History
229 lines (176 loc) · 9.49 KB

tools.md

File metadata and controls

229 lines (176 loc) · 9.49 KB

Complementary Tools

fd: search for a file name

Some projects are split across numerous deeply-nested directories; it is common to remember the file name but not the directory where it lives. fd can be used within Acme to search for a file name. For example, executing (mouse-2) fd 9 in an Acme window whose PWD is this repository yields a +Errors window with the following contents:

./bin/9a
./bin/9s

Mouse-3 on the file name will open it within Acme. fd has many useful options to limit searching to files with certain types, extensions, etc.

While find can also be used, fd is faster and Git-aware (by default it ignores the .git directory and everything listed in .gitignore). fd is available as a package on most Unix-like systems; on Debian-based Linux distributions, the package is fd-find and the executable is fdfind.

rg: recursive search for string or regex

ripgrep (rg) can be used within Acme to search for a string. For example, executing (mouse-2) rg --vimgrep AUTHOR in an Acme window whose PWD is this repository yields a +Errors window with the following contents:

LICENSE:6:42:THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
LICENSE:8:37:AND FITNESS.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,

With --vimgrep, rg outputs the line and column numbers. Mouse-3 on the file:line:column in the output (e.g., LICENSE:6:42) opens the file in Acme and positions the cursor on the line and column number where the search term was found. To avoid repeatedly typing --vimgrep, a wrapper script for rg can be created (like this one).

While grep -R can also be used, rg is faster and Git-aware (by default it ignores the .git directory and everything listed in .gitignore). rg is available as a package (sometimes called ripgrep) on most Unix-like systems.

codesearch: indexed search for string or regex

rg (see above) has to read every file in the directory being searched. That can take a while if searching a large code base (in particular if the files are not cached). By contrast, codesearch creates an index that allows it to "identify a set of candidate documents and then run the full regular expression search against only those documents." This can be faster although these days with SSDs and lots of RAM for caching it won't be a huge difference in most cases.

To install codesearch, you have to have Go. Then:

go install github.com/google/codesearch/cmd/...@latest
# Older versions of Go might need to do this instead:
go get github.com/google/codesearch/cmd/...

codesearch has two executables, cindex and csearch. cindex is used to index (or reindex) a directory, e.g.:

cindex $PLAN9/src

Then csearch is used to search the indexed directories, e.g.:

% csearch -n scrlresize
/usr/local/plan9/src/cmd/acme/acme.c:553:                       scrlresize();
/usr/local/plan9/src/cmd/acme/fns.h:17:void     scrlresize(void);
/usr/local/plan9/src/cmd/acme/scrl.c:47:scrlresize(void)
/usr/local/plan9/src/cmd/acme/scrl.c:64:                scrlresize();

Both commands can easily be run within Acme, in a win shell or from the tag bar. As with grep, csearch needs an -n option to print the line number, which is desirable within Acme since it allows using mouse-3 to jump to the line.

The above example used the plan9port source tree, but it's too small for codesearch to have a speed advantage on modern hardware. On the machine I'm typing this on, csearch scrlresize completed in 0.00 seconds, but rg scrlresize only takes 0.02 seconds (warm cache). Even on the much larger Linux kernel source tree, rg finishes in less than a second (warm cache) with any query: csearch is even faster, but rg is often fast enough. (grep is slower than either csearch or rg.)

While the theoretical speed advantages may not always be appreciable in practice, codesearch has another useful property: by default it adds all indexed directories to an index at HOME/.csearchindex. This allows using csearch to search across directories that are scattered around the file system. For example, you could index directories such as:

cindex $PLAN9/src
cindex $HOME/src/linux/torvalds
cindex /usr/include

With that, csearch foobar would search for "foobar" in all of those directories. The same can be accomplished with rg or grep, but it would be necessary to explicitly list the directories to be searched; using csearch is more convenient. cindex continues to be very fast even when many large source directories are indexed, so it's safe to index all your source trees. A functionally comparable shell script which ran rg across all your source trees would become linearly slower as more source was added and would cause many files to be read into the cache that you were't using (possibly evicting more useful cached files).

ctags: jump to definition

ctags "generates an index (or tag) file of language objects found in source files for programming languages." In effect, it creates an index of where objects are defined; with C, the indexed objects include functions, global variables, macros, types, enumerations, and structure members. ctags supports around 135 programming languages.

It is possible to use ctags within Acme to provide "jump to definition" functionality. The first step is to create the tags file, e.g.:

cd $PLAN9/src/cmd/acme
ctags -R

The tags file stores the location of each object as a pattern rather than by line number, so it does not immediately become out-of-date as lines are inserted or removed. However, when object definitions are modified or moved between files, the tags file will become stale and need to be regenerated. Fortunately, ctags is fast.

Unlike some other editors, Acme does not natively support reading from the tags file, but this can be done with a script. The one I use is called tag. Continuing the previous example:

% tag readfile
/usr/local/plan9/src/cmd/acme/acme.c:286
/usr/local/plan9/src/cmd/acme/mail/mesg.c:333

Although tag can be run in a terminal or win shell, normally I use it in the tag bar with the 2-1 mouse chord. To do so, add "tag" to a window with an appropriate directory (i.e., the tags file must exist in the same directory or one of its parent directories). In the source code window, double-click (mouse-1) on the symbol to be looked up. Then mouse-2 click and hold on the tag in the tag bar, and (with mouse-2 still held down) mouse-1 click to pass the selection as an argument to tag, then release both mouse-1 and mouse-2 (in either order). If at least one definition is found, the filename:lineno will be output to the +Errors window, and can be mouse-3 clicked to open.

ctags is available as a package on most Unix-like systems; it might be called universal-ctags to distinguish it from the older unmaintained exuberant-ctags. On macOS, be aware that Xcode includes /usr/bin/ctags, which is an older implementation, whereas Homebrew installs its universal-ctags at either /usr/local/bin/ctags (Intel) or /opt/homebrew/bin/ctags (Apple Silicon): be sure to run the Homebrew version.

Other development tools (TODO)

TODO: Research using the following with Acme and describe them here if they are useful.

ssh and sshfs: remote editing

Acme is a GUI program which complicates editing files on a remote host, but only slightly.

SSH X11 forwarding

ssh implements X11 forwarding, which allows the local client to render X11 applications running on the remote host. This is the traditional method of running GUI applications in an ssh session. X11 forwarding must be enabled both on the client and the remote:

  • The remote must have X11Forwarding yes in its /etc/ssh/sshd_config. If sshd_config is edited to change this, sshd must be restarted.
  • The client must connect with ssh -X or have ForwardX11 yes in $HOME/.ssh/config.

With X11 forwarding, you can ssh -X into the remote host and run its local copy of Acme as usual. However, this has several limitations:

  • It requires that the remote host has plan9port installed.
  • There is a noticeable UI lag, even for nearby hosts.
  • Acme running on the remote host will only have access to the remote file system. Often it would be more useful to have both local and remote files in the same text editor session.

SSHFS

SSHFS is a more convenient solution for editing files on remote systems. It uses SSH and FUSE to mount a remote directory in the local file system. This allows any local application (including Acme) to access the remote files as if they were local files. Basic sshfs usage is simple:

sshfs [user@]hostname:[directory] mountpoint

[user@] if omitted defaults to the local username and [directory] if omitted defaults to the user's home directory.