Browsing Source Code

Home About GitHub

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...

  1. switch to my terminal emulator window

  2. run a new Bash process in a new Tmux window

  3. cd other-projects to switch to my directory for other people's projects that I like to try out

  4. Assuming the project is under Git revision control, I inspect the Git status, and perhaps the git log.

    git status
    git log
          
  5. I cd into a cloned Git directory and browse the README file.

    less README*
          
  6. 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 like

              tree | 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.

  7. 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...

  1. My Emacs session is always open, so I context switch to it if I am not already there.

  2. 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>
          
  3. 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).

  4. Next I use Magit (pronounced like magic but with a t 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 commits

    • I use q to exit the details of an individual commit.

  5. 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 in view (read-only) mode, similar to the less command.

  6. When I am through with the README file, I close it with C-x k, similar typing q in the less command.

  7. 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 i key to insert the output of the ls 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 type C-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 the ls command on all directory subsections currently listed in the buffer.

    When I want to run the find command, 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 .hs file extension. I can navigate this list using most of the same commands that were mentioned before.

  8. 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 using M-g n or M-g p, or by navigating the *compilation* buffer with the arrow keys and pressing enter on a highlted error message.

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:


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.