Browsing Source Code
Browsing Source Code
Suppose you come across a Git repository for interesting project, and you want to browse the source code, what is the first thing you do? This article demonstrates what I do to browse through source code from GitHub:
This article is a complement to another article I wrote in this
series called Emacs as your
shell
.
As a command line user...
switch to my terminal emulator window
run a new Bash process in a new Tmux window
cd other-projects
to switch to my directory for other people's projects that I like to try outAssuming the project is under Git revision control, I inspect the Git status, and perhaps the git log.
git status git log
I
cd
into a cloned Git directory and browse the README file.less README*
-
After that, I might browse around the various subdirectories trying to get a feel of the layout of the project. I look for things like what programming languages and build system is used, and where are the source files are.
I might browse around the various subdirectories trying to get a feel for the layout of the project. I might try lots of
ls
commands, or perhaps something liketree | less #(or perhaps)# find . -maxdepth 2 -type f | less
and then within
less
I can use the interactive search function/
to look around for keywords. I may want to try to build the project, so I will do this from within Vim, I run the command
vim project.cabal
and enter the vim commands::set makecmd=cabal\ v2-build :make
This launches a Make build process, and captures all log output which you can inspect in the event of a problem. It may even parse out file and line numbers so you can navigate to the location of the problem.
As an Emacs user...
My Emacs session is always open, so I context switch to it if I am not already there.
I use Dired (I pronounce it "Dir--Ed", the directory editor) to go to the
other-projects
directory, my directory for other people's projects that I like to try out.C-x d <Ret> ;; Dired prompts for a directory C-x h <Backspace> ;; Erase the default path in the prompt ~/other-projects ;; Type the directory (tab completion helps)
Chances are this directory is already open in a buffer, and I could have switched to it using:
C-c b other- <Tab> <Ret>
Once I am in a Dired buffer, this buffer will serve as my starting point for all subsequent editing commands. Every time I need to see my project directory, I switch back to this buffer. It is a similar technique to creating a new Tmux window with a shell dedicated to the task of browsing that source code.
I can also visit any file in the project, and run any shell command from within this directory.
Personally, I have no need for an always-visible source tree on the left of the screen like what many editors show (and what the Emacs
NeoTree
extension does).Next I use Magit (pronounced like
magic
but with at
at the end) to see a Git log:M-x magit-status <Ret>
I use arrow keys and
Enter to look at the log of individual commitsI use
q to exit the details of an individual commit.
I switch back to the Dired buffer and start browsing files. Instead of
ls
as I would use on the command line, I use the arrow keys, or the>
or<
keys to navigate to interesting-looking directories,>
and<
move the cursor only to directories, skipping over files.I press
j
which promps me for a filename (with tab completion) that I want to view, then I navigate the cursor to the README file:READ <Tab> <Ret>
With the cursor on the README file, I press
v
to open the README file inview
(read-only) mode, similar to theless
command.-
I might browse around the various subdirectories trying to get a feel for the layout of the project. I look for things like what build programming languages and system is used, and where are the source files.
I navigate to an interesting looking directory with
<
then press thei
key toinsert
the output of thels
command in a new subsection at the bottom of the buffer, where I can navigate it with the arrow keys. The subsection header is the name of the directory.If the directory turns out to be uninteresting, I type
C-M-p
to move the cursor to the directory name for this subsection header and typeC-u k
to delete the subsection. I could also press$
to fold-up or fold-down that subsection.If the directory is interesting, but I want to navigate the cursor back to the parent directory, I press
^
to navigate to the parent directory of the current subsection.I can press
g
at any time to refresh the directory view. This will re-run thels
command on all directory subsections currently listed in the buffer.When I want to run the
find
command, I typeM-x find-dired <Ret>
and enter my query:find -type d -name .git -prune -false -o -name '*.hs'
This will list all Haskell source code files (files ending with the
.hs
file extension. I can navigate this list using most of the same commands that were mentioned before. -
I can try to build the project using
M-x compile <Ret>
, which prompts for an executable command, so I enter:cabal v2-build
This captures the build log output into a new buffer called
*compilation*
, and it may even highlight line numbers if errors or warnings occur, which I can navigate to usingM-g n
orM-g p
, or by navigating the*compilation*
buffer with the arrow keys and pressing enter on a highlted error message.
When I am through with the README file, I close it with C-x
k
, similar typing q
in the less
command.
Summary
In my opinion, there are a few advantages of using Emacs over an ordinary shell-based workflow to a common, day-to-day task like browsing a directory of files. For example:
Dired captures all of the output of
ls
in an in-memory buffer, and allows you to navigate with cursor motion and tab completion, rather than relying entirely on tab completion as you would in an interactive REPL such as Bash.Using a Dired buffer that you never close keeps a reference to the directory you are exploring, similar to how a Tmux window can be used created and dedicated to navigating the directory with an interactive REPL.
You can view arbitrary files and subdirectories, as well as launch shell processes at any time from within the Dired directory, usually with fewer keystrokes than with an interactive REPL.
There are user interfaces built around tools like Find and Grep that make navigation using these tools easier.
Emacs for Professionals
This article is part of my Emacs for Professionals series, in which I explain in a few paragraphs how I perform a specific common task using Emacs in ways that people already familiar with command line tools and Linux shell scripting can quickly understand.