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
Emacs as your
As a command line user...
switch to my terminal emulator window
run a new Bash process in a new Tmux window
cd other-projectsto switch to my directory for other people's projects that I like to try out
Assuming the project is under Git revision control, I inspect the Git status, and perhaps the git log.
git status git log
cdinto a cloned Git directory and browse the README file.
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
lscommands, or perhaps something like
tree | less #(or perhaps)# find . -maxdepth 2 -type f | less
and then within
lessI 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.cabaland 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-projectsdirectory, 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
Next I use Magit (pronounced like
magicbut with a
tat the end) to see a Git log:
M-x magit-status <Ret>
I use arrow keys and
Enterto look at the log of individual commits
qto exit the details of an individual commit.
I switch back to the Dired buffer and start browsing files. Instead of
lsas I would use on the command line, I use the arrow keys, or the
<keys to navigate to interesting-looking directories,
<move the cursor only to directories, skipping over files.
jwhich 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
vto open the README file in
view(read-only) mode, similar to the
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 the
insertthe output of the
lscommand 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-pto move the cursor to the directory name for this subsection header and type
C-u kto 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
gat any time to refresh the directory view. This will re-run the
lscommand on all directory subsections currently listed in the buffer.
When I want to run the
findcommand, I type
M-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
.hsfile 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:
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 using
M-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
k, similar typing
q in the
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
lsin 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.