Skip to content

Instantly share code, notes, and snippets.

@MilesCranmer
Last active June 21, 2017 03:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MilesCranmer/6695a9196376665aa6a08b3451d5c919 to your computer and use it in GitHub Desktop.
Save MilesCranmer/6695a9196376665aa6a08b3451d5c919 to your computer and use it in GitHub Desktop.
Programming tricks

Favorite tricks

(These are ranked in order of favourites)

Getting includes automatically in C

Set up ctags:

apt-get install exuberant-ctags
#Then, in the directory of interest,
ctags -R

Say you have a list of types and variables from lines 25,38 (say you are building a struct):

 cal_context_t  calibration_info;                                            
 cal_context_t  simulation_info;                                             
 group_timer_t  tGroup;                                                      
 mwahpx_acc_context_t  **output_accumulations;                               
 mwahpx_acc_context_t  *the_accumulator;                                     
 obs_context_t  **context_list;                                              
 pixelgrid_t  *rubber_sheet;                                                 
 primary_beam_t  *reference_beam;                                            
 regrid_context_t  *regrid_ctxt;                                             
 rts_options_t  rts_options;                                                 
 source_info_t  *dummy_source;                                               
 stokes_context_t  *stokes_ctxt;                                             
 vis_set_t  **chanvis;                                                       
 vis_set_t  *bandvis;  

Now, there's a huge problem. You have no idea where these things are defined.

So, run the following:

:25,38g/./exe "norm! 0wl\<c-]>:let @k = expand(\"%\")\<enter>\<c-t>ggo#include \"\<esc>\"kpa\""

There are two important steps here. The rest of it is normal vim:

\<c-]>

With the type name under the cursor, <c-]> uses ctags to bring up the file of its definition. Then,

:let @k = expand(\"%\")\<enter>\<c-t>

This puts the filename into register k, and then <c-t> brings us back to our initial file.

This will grab every include file you need and put them at the top of the file:

#include "rts_common.h"
#include "rts_common.h"                                                         
#include "pix_pol_conversions.h"                                                
#include "CalSourceList.h"                                                      
#include "rts_common.h"                                                         
#include "regrid_engine.h"                                                      
#include "rts_common.h"                                                         
#include "ionospheric_corrector.h"                                              
#include "obs_context_t.h"                                                      
#include "mwahpx.h"                                                             
#include "mwahpx.h"                                                             
#include "timer.h"                                                              
#include "cal_context_t.h"                                                      
#include "cal_context_t.h" 

Magic.

Fixing undeclared symbol errors automatically

One time I was refactoring legacy C code, and ended up just cutting about 300 lines out of an ugly function and putting it somewhere else. Not knowing which variables it needed, I let make tell me. There was about 40 missing variables.

It mostly looked like this:

mwa_sim_functions.c:327:72: error: ‘dummy_source’ undeclared (first use in this function)
           grid_number, grid_size_meters, reference_beam, rubber_sheet, dummy_source,
                                                                        ^
mwa_sim_functions.c:328:12: error: ‘stokes_ctxt’ undeclared (first use in this function)
           &stokes_ctxt, &regrid_ctxt, integration_file, output_accumulations, the_accumulator,
            ^
mwa_sim_functions.c:328:26: error: ‘regrid_ctxt’ undeclared (first use in this function)
           &stokes_ctxt, &regrid_ctxt, integration_file, output_accumulations, the_accumulator,
                          ^
mwa_sim_functions.c:328:39: error: ‘integration_file’ undeclared (first use in this function)
           &stokes_ctxt, &regrid_ctxt, integration_file, output_accumulations, the_accumulator,
                                       ^

So, I copy pasted this into vim right under the declaration of the pasted function (at line 193), and ran the following, with the error highlighted:

:'<,'>v/error/d
<esc>
qa0mx/error<enter>f:lllyiw/^int<enter>Op*yy'xPq
22@a
:'<,'>g/^m/norm mxk^yw193ggA ^[p'xfef:lllyiw193ggA ^[pA,

The first command just deletes every line that doesn't have "error" in it.

The second command is a bit terrifying. I record a macro to run on each line of the error message: it grabs the variable name (yiw), goes back to the original function (/^int<enter>), pastes the variable, types * to do a forward search on the variable name, then grabs the line with the first occurence, and pastes it above the error message ('xP)

This always seems to get the type of the variable.

Then, I run it 22 times more to get all the types. Magic.

Then, I run another ugly command to basically grab the type (the first symbol on the line above each error message, ^m) and then append it to line 193, then grab the symbol name again, and paste it after that. Then type a comma. This gets executed on every error message, so I end up with an almost working function with all of its missing variables as arguments.

When can contextual code-completion do this for me?

:g

:g in vim is very powerful. It lets you use useful "ex" commands on lines matching a substring.

E.g., to make copies of all variables with the suffix _a, but with _b, below the current line, type:

:1,6g/_a/t.|s/_a/_b/g

to search through lines 1,6 for the string _a, then copy (t) to below (.) the copied line, then (|) search for _a, and replace with _b all copies (g).

Another, to delete the last subfields in a comma-delimited file, and add "bar" to all lines matching "foo":

:'<,'>g/foo/norm $F,F,d0ibar

When highlighting a bunch of lines, type :, then g to load up the start of this command, then /foo to get lines only with that string, then norm to enter normal mode on each line, then you can type normal vim commands $F,F,d0ibar to go to the end of the line ($), go to the previous comma twice (F,F,), then delete to the start of the line (d0), the insert the word bar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment