Emacs Rust Development Setup

========BASIC SETUP===========

=======PROJECT SETUP==========
Read the Cargo guide.

=======GGTAGS SETUP==========

For cross referencing via ggtags:

  1. Download and install Gnu Global (the Gnu Global package available in Ubuntu 14.04 doesn’t allow adding new lang defs).
  2. Ensure that $HOME/.ctags includes the Rust lang definitions from ctags.rust.
  3. Set the env variable GTAGSCONF to $HOME/.globalrc
  4. Set the env variable GTAGSLABEL to ctags, e.g. export GTAGSLABLE=”ctags”
  5. Sometimes eshell in emacs doesn’t inherit the env variables, in which case run gtags . in a normal shell.
  6. To .emacs add
    (add-hook 'prog-mode-hook
          '(lambda ()
             (when (derived-mode-p 'rust-mode) 
    	 (ggtags-mode 1))))
    	 
    
  7. Copy to .globalrc
    # Configuration file for GNU GLOBAL source code tag system.
    #
    # Basically, GLOBAL doesn't need this file ('gtags.conf'), because it has
    # default values in its self. If you have the file as '/etc/gtags.conf' or
    # "$HOME/.globalrc" in your system then GLOBAL overwrite the default values
    # with the values in the file.
    #
    # The format is similar to termcap(5). You can specify a target with
    # GTAGSLABEL environment variable. Default target is 'default'.
    #
    default:\
    	:tc=native:
    native:\
    	:tc=gtags:
    ctags:\
    	:tc=exuberant-ctags:
    #---------------------------------------------------------------------
    # Configuration for gtags(1)
    # See gtags(1).
    #---------------------------------------------------------------------
    common:\
    	:skip=HTML/,HTML.pub/,tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,SCCS/,RCS/,CVS/,CVSROOT/,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake:
    #
    # Built-in parsers.
    #
    gtags:\
    	:tc=common:\
    	:tc=builtin-parser:
    builtin-parser:\
    	:langmap=c\:.c.h,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.hh.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml:
    #
    # Plug-in parser to use Exuberant Ctags.
    #
    exuberant-ctags|plugin-example|setting to use Exuberant Ctags plug-in parser:\
    	:tc=common:\
    	:langmap=Asm\:.asm.ASM.s.S:\
    	:langmap=Awk\:.awk.gawk.mawk:\
    	:langmap=C\:.c:\
    	:langmap=C++\:.c++.cc.cp.cpp.cxx.h.h++.hh.hp.hpp.hxx.C.H:\
    	:langmap=Flex\:.as.mxml:\
    	:langmap=HTML\:.htm.html:\
    	:langmap=Java\:.java:\
    	:langmap=JavaScript\:.js:\
    	:langmap=Lisp\:.cl.clisp.el.l.lisp.lsp:\
    	:langmap=Perl\:.pl.pm.plx.perl:\
    	:langmap=Python\:.py.pyx.pxd.pxi.scons:\
    	:langmap=Ruby\:.rb.ruby:\
            :langmap=Rust\:.rs:\
    	:langmap=Scheme\:.SCM.SM.sch.scheme.scm.sm:\
    	:langmap=Sh\:.sh.SH.bsh.bash.ksh.zsh:\
    	:langmap=YACC\:.y:\
    	:gtags_parser=Asm\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Awk\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=C\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=C++\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Flex\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=HTML\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Java\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=JavaScript\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Lisp\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Perl\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Python\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Ruby\:/usr/local/lib/gtags/exuberant-ctags.la:\
            :gtags_parser=Rust\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Scheme\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=Sh\:/usr/local/lib/gtags/exuberant-ctags.la:\
    	:gtags_parser=YACC\:/usr/local/lib/gtags/exuberant-ctags.la:
    

======================TIPS======================
Usable keyboard shortcuts for navigation, with Rust code:

  • M-.       – ggtags-find-tag-dwim – Go to definition
  • C-c M-g – ggtags-grep              – Grep for references

Bind ggtags-grep to “M-]”, for finding references:

(add-hook 'prog-mode-hook
      '(lambda ()
         (when (derived-mode-p 'rust-mode)
           (define-key ggtags-mode-map (kbd "M-]") 'ggtags-grep)
           )))

Screencast

I’ve uploaded a screencast demonstrating the capabilities of a quickbooks sync application that I wrote. The video is at link

There are several issues with the screencast that I want to fix before I upload my next one.

1. The audio is out of sync with the video. I’ll have to fiddle around with the settings for CamStudio to try and fix this. It’s also possible that my computer is just too old and getting a faster computer would fix this problem.

2. The uploaded video has blurry text. I tried uploading the AVI video that CamStudio generates to Google video and Youtube. Youtube generated a better result from the Avi video. But I’m still not happy. I might try creating the video with a different resolution or maybe try Vimeo which I believe has higher resolution videos.

Anyways it was a fun experience creating a screencast and I’m sure to do it again.

Database Wrapper Objects

It’s common to use small wrapper objects around database tables. One object represents one row in the database table. For the sake of clarity the following is a simple example:

Database: Documents table, with columns (Id, FileName, Data). Where Id is an identifier for the object, I use a <a href=”http://en.wikipedia.org/wiki/Guid”>Guid</a&gt;.

A simple wrapper object for the Documents table would have the following pseudo code

class Document {
property Id
prpoerty FileName
property Data
}

The only issues are how to create new Document objects, how to save Document objects, and how to retrieve Document objects.

Since I’m young and stupid I had the wrong solution for all three problems.
First I created a separate Database class with static methods for Retrieving, Adding, & Updating Document objects. This becomes unmanageable when the number of wrapper objects for the database gets above 10.

The correct solution is to
1. Create a Save() method for the Document class that intelligently either adds the document to the database or updates the existing document in the database. Thus the user of the document class doesn’t need to remember if they’re updating an existing document or creating a new document.

2. Have a single constructor for the Document class that accepts an Id. This constructor then creates a new Document object if that Id does not exist in the database or retrieves the existing Document object from the database if that Id is in the database.

By doing the above the creation and saving of Document objects is entirely consistent. This reduces the cognitively load on users of the Document class so they don’t have to think about the details of how Document objects are created and stored, instead they can concentrate their effort on other things.

Software Installation and Configuration

I know I’m supposed to continue with my series of posts on 2D geometry algorithms but I’ve been busy (mostly lazy, but I’ll blame being busy :). Infact this post is about what I’ve been wasting time on. And that’s Software Installation and Configuration.

First a little background. I routinely use 3 different computers. My home desktop computer, work laptop, and home laptop. I also have server space that I use at hostmonster.com. I do software develop on all 4 systems.

This means that I have 4 systems to configure. The pain of installing and configuring the software becomes a huge annoyance. I estimate that I spend at least 20% of my time just installing or configuring software (this includes installing new versions of packages such as ruby on rails). When you think about it, this is a huge problem. That 20% of my time is completely wasted. I’m not doing creative or productive work. It’s the part of my work that I hate the most (actually the only part that I dislike about my work). I’m writing this blog because I just upgraded my home desktop computer and it’s taken me almost two days to get everything configured (this does include some time I spent on hardware issues).

I know of several other people that have written about this problem (or very similar problems). Steve Yegge cites someone here (search for “configuration”). Part of the ruby on rails philosophy is convention over configuration.

This is part of the reason why web apps have grown so popular. With web apps you don’t have to reinstall or configure software when switching computers (except for the web browser but that’s only one app). You don’t even have to worry about lugging your data around. It’s all stored on the server and available anywhere.

I don’t know of any really good solutions to this problem for thick client apps (it’d be great if people in the comments would link to possible solutions). One method is to create a set of unattended scripts to automate the installation and configuration of my development tools. But then there’s the problem that my home desktop computer runs Ubuntu and unattended is for windows.

One solution is to copy squeak’s model of keeping all your development tools inside one big binary blog that you can cart around. You can do this via virtual machines (squeak runs on its own virtual machine). That is create one disk image that you use on every computer and run that disk image using your favorite virtual machine (I use VMware). The downside to this solution is that you have to cart around an at least 20GB file. Also you need a disk image for every operating system you use.

Another possibility is to follow Mac OS X’s use of apps as directories. This is where each application resides entirely in one directory. So to copy the app you just copy its folder. There exists a Linux program ROX that also uses the apps as directories philosophy. There’s another Linux program Zero Install that largely eliminates software installation. Here’s a Zero Install example (stolen from Wikipedia):

http://www.vim.org/vim textfile.txt”

The above will run “vim textfile.txt”. More importantly you don’t have to worry if vim is already installed or not. If vim is not installed it gets automatically installed with I believe no user interaction. Too bad zero install doesn’t exist for windows. There is still the problem of configuration that I don’t believe Zero Install fixes.

One partial solution to the configuration problem is to set up a git repository of all your configuration files and then on each computer do a “git pull” (or “git clone” if it’s the first time) to fetch the configuration files (you’d also need to write some scripts to copy the files to the appropriate places).

I imagine that with a lot (probably an enormous amount) of engineering it would be possible to use a git like repository for the whole operating system. Then for each computer you’d do a “git pull” to get the most recent version of all you programs and configuration files.

Too bad I don’t have the resources to execute that idea. Because I really hate software installation and configuration.
Feel free point out anything that would alleviate my pain.