Slick-C Macros

kohei_write_enum_switch

This macro inserts an entire switch statement block for an arbitrary enum type. It includes case blocks for all members of the specified enum type.

#include "slick.sh"
#include "tagsdb.sh"
 
_command void kohei_write_enum_switch(_str enum_name = '') name_info(COMMAND_ARG',')
{
   if (!ext_inherits_from('c')) {
      message("not in c mode");
      _beep();
      return;
   }
 
   if (enum_name == '') {
      int res = textBoxDialog("Provide tag name", 0, 0, "", "", "kohei_write_enum_switch", "tag name");
      if (res == COMMAND_CANCELLED_RC) {
         // Dialog cancelled.  Abort.
         message("command cancelled");
         return;
      }
      enum_name = _param1;
      if (enum_name == '') {
         // Name is still empty.  Abort.
         message("no tag name is given");
         return;
      }
   }
 
   _str inner_name, outer_name;
   tag_split_class_name(enum_name, inner_name, outer_name);
 
   typeless tag_files = p_window_id.tags_filenamea(p_window_id.p_LangId);
   if (!tag_check_for_enum(inner_name, outer_name, tag_files, p_EmbeddedCaseSensitive))
   {
      message(enum_name" is not of type enum.");
      _beep();   
      return;
   }
 
   // Collect enum member names from the tag files.
   _str enum_members[];
   enum_members._makeempty();
   int i = 0;                                            
   for (;;) {                                           
      _str tf = next_tag_filea(tag_files, i, false, true);
      if (tf == '') 
         break;                               
 
      int status = tag_find_in_class(enum_name);
      while (!status) {
         _str tag_name, type_name, file_name, class_name;
         int line_no, tag_flags;
         tag_get_info(tag_name, type_name, file_name, line_no, class_name, tag_flags);
         if (type_name == "enumc") {
            // Only pick up enum members.
            enum_members[enum_members._length()] = tag_name;
         }
         status = tag_next_in_class();
      }
   }
 
   // Now, insert a switch statement using the member names.  When doing so, 
   // keep extending the selection and run beautify on the selected lines to 
   // get the indentation correctly.
 
   insert_line("switch ("inner_name")");
   select_line();
   insert_line("{");
   int memcount = enum_members._length();                                 
   for (i = 0; i < memcount; ++i) {
      insert_line("case "enum_members[i]":");
      insert_line("break;");
   }
   insert_line("default:");
   insert_line(";");
   insert_line("}");
   beautify_selection();
}

The following are the rest of my custom Slick-C macro commands that I have yet to annotate.

#include "slick.sh"
#include "tagsdb.sh"
 
_command void kohei_header_guard() name_info(',')
{
   if (p_buf_name == '') {
      message("buffer name is empty.");
      return;
   }
   _str cur_file_name = stranslate(p_buf_name, '', '.*/', 'u');
   cur_file_name = upcase(stranslate(cur_file_name, '_', '.'));
 
   _insert_text_raw('#ifndef __'cur_file_name'__');
   insert_line('#define __'cur_file_name'__');
   insert_line('');
   insert_line('');
   typeless p;
   _save_pos2(p);
   insert_line('');
   insert_line('#endif');
   _restore_pos2(p);
}
 
_command void kohei_write_class_dec(_str name='') name_info(COMMAND_ARG',')
{
   if (name == '') {
      // no class name given
      return;
   }
 
   _insert_text_raw('class 'name);
   insert_line('{');
   insert_line('public:');
   insert_line(name'();');
   indent_line();
   insert_line('~'name'();');
   indent_line();
   insert_line('private:');
   end_line();
 
   // save this position to come back later.
   typeless p;
   _save_pos2(p);
 
   insert_line('};');
   insert_line('');
 
   // constructor
   insert_line(name'::'name'()');
   insert_line('{');
   insert_line('}');
 
   // destructor
   insert_line(name'::~'name'()');
   insert_line('{');
   insert_line('}');
 
   // go back to the saved position.
   _restore_pos2(p);
}
 
_command void insert_date_today() name_info(',')
{
   int pin, pout, perr;
   _str datecmd = "/bin/date";
   _str cmd = datecmd :+ " +%Y-%m-%d";
   _str output = _PipeShellResult(cmd, 0, '');
   output = substr(output, 1, length(output)-2);
   cmd = datecmd :+ " +(%A)";
   output = output :+ " " :+ _PipeShellResult(cmd, 0, '');
   output = substr(output, 1, length(output)-2);
   _insert_text(output, false, "\n");
}
/** 
 * Reflow paragraph based on the current margin settings, with 
 * the option to specify left indent level.
 * 
 * @param indent indent level
 */
_command void kohei_reflow_paragraph(_str indent='') name_info(COMMAND_ARG',')
{
   _str extName = 'fundamental';
 
   if (!ext_inherits_from(extName)) {
      message("this command only works for fundamental mode.");
      return;
   }
 
   // Launch input dialog when no argument is given.
   if (indent == '') {
      int res = textBoxDialog("Indent Level", 0, 0, "", "", 
                              "reflow_paragraph_left_indent", "indent level:0");
      if (res == COMMAND_CANCELLED_RC) {
         // Dialog cancelled.  Abort.
         message("command cancelled");
         return;
      }
      indent = _param1;
   }
 
   // The indent must be a number.
   if (!isnumber(indent)) {
      message("'"indent"' is not a number.");
      return;
   }
   int indentLevel = (int)indent;
 
   // Set current extention options.
   VSEXTSETUPOPTIONS oldSetup;
   int setup_status = _ExtGetSetup(extName, oldSetup);
   if (setup_status) {
      // Failed to get the setup.
      return;
   }
 
   _str leftMargin, rightMargin, newparaMargin;
   parse oldSetup.margins with leftMargin' 'rightMargin' 'newparaMargin;
   if (!isnumber(leftMargin) || !isnumber(rightMargin) || !isnumber(newparaMargin)) {
      message("corrupt margin settings");
      return;
   }
 
   int leftMarginN    = (int)leftMargin;
   int newparaMarginN = (int)newparaMargin;
 
   int indentUnit = newparaMarginN - leftMarginN;
   if (indentUnit < 0) {
      indentUnit *= -1;
   } else if (indentUnit == 0) {
      // default indent unit length is 2.
      indentUnit = 2;
   }
 
   leftMarginN    += indentUnit * indentLevel;
   newparaMarginN += indentUnit * indentLevel;
 
   // Set new margin settings.
   VSEXTSETUPOPTIONS newSetup = oldSetup;
   newSetup.margins = leftMarginN :+ ' ' :+ rightMargin :+ ' ' :+ newparaMarginN;
   _ExtSetSetup(extName, newSetup);
   _update_buffers(extName);
 
   reflow_paragraph();
 
   // Restore the old setup.
   _ExtSetSetup(extName, oldSetup);
   _update_buffers(extName);
}
 
/**
 * Set active the specified project by its name, without the 
 * .vpj extension.  So, to activate 'foo.vpj', this command 
 * expects 'foo' as the input.  If there are multiple projects 
 * with the same name, it activates the first project it finds. 
 * 
 * @param name name of the project to activate
 */
_command void set_active_project(_str name='') name_info(COMMAND_ARG',')
{
   if (name == '') {
      int res = textBoxDialog("Activate Project", 0, 0, "", "", "set_active_project", "project name");
      if (res == COMMAND_CANCELLED_RC) {
         // Dialog cancelled.  Abort.
         message("command cancelled");
         return;
      }
      name = _param1;
      if (name == '') {
         // Name is still empty.  Abort.
         message("specified project name is empty");
         return;
      }
   }
 
   // Load the workspace XML file of the current workspace.
   int status = 0;
   int handle = _xmlcfg_open(_workspace_filename, status);
   if (status < 0) {
      message("failed to load workspace file");
      return;
   }
 
   // Go through all project names.
   _str projFiles[];
   _WorkspaceGet_ProjectFiles(handle, projFiles);
   int i, n = projFiles._length();
   for (i = 0; i < n; ++i) {
      _str projName = stranslate(projFiles[i], '', "?*/", "r");
      projName = stranslate(projName, '', "\\.vpj$", "r");
      if (name == projName) {
         // Matching project name found.  Set this project active.
         workspace_set_active(projFiles[i]);
         return;
      }
   }
 
   message("no project named '"name"' found");
}
 
/** 
 * Look up a symbol using OpenGrok.
 * 
 * @param symbol_name Symbol name to look up.  Leave it blank to 
 *                    just go to OpenGrok's main page.
 */
_command void ooo_grok(_str symbol_name='') name_info(COMMAND_ARG',')
{
   _str baseurl = 'http://svn.services.openoffice.org/opengrok/';
   if (symbol_name == '') {
      goto_url(baseurl, true);
   } else {
      goto_url(baseurl'search?project=%2FCurrent+(trunk)&defs='symbol_name, true);
   }
}
 
/** 
 * Look up UNO API using the on-line IDL reference.  The namespaces must be 
 * separated by '.', and the com.sun.star namespace needs to be omitted. 
 * 
 * @param api_name
 */
_command void ooo_api(_str api_name='') name_info(COMMAND_ARG',')
{
   _str baseurl = 'http://api.openoffice.org/docs/common/ref/com/sun/star';
   if (api_name == '') {
      goto_url(baseurl'/module-ix.html', true);
   } else {
      _str relurl = stranslate(api_name, '/', '.');
      goto_url(baseurl'/'relurl'.html', true);
   }
}
 
/**
 * Insert an fprintf statement that contains the current class and method 
 * names, and set the cursor to the right position ready for typing a comment 
 * in.
 */
_command void c_insert_class_method_debug_statement() name_info(',')
{
   _str cur_class = current_class(0);
   _str cur_proc = current_proc(0);
   if (cur_class != '') {
      // inside class context.
      cur_class = stranslate(cur_class, '', '^[a-zA-Z\/]@\/', 'r');
      _insert_text('fprintf(stdout, "'cur_class'::'cur_proc':   ');
   } else {
      // stand-alone function.
      _insert_text('fprintf(stdout, "'cur_proc':   ');
   }
 
   typeless p;
   _save_pos2(p);
   _insert_text('\n");');
   _restore_pos2(p);
}
 
_command void c_insert_class_method_debug_statement_win32() name_info(',')
{
   _str cur_class = current_class(0);
   _str cur_proc = current_proc(0);
   _insert_text('{ char tmp[256]; sprintf(tmp, "');
   if (cur_class != '') {
      // inside class context.
      cur_class = stranslate(cur_class, '', '^[a-zA-Z\/]@\/', 'r');
      _insert_text(cur_class'::'cur_proc':   ');
   } else {
      // stand-alone function.
      _insert_text(cur_proc':   ');
   }
 
   typeless p;
   _save_pos2(p);
   _insert_text('\n"); OutputDebugStringA(tmp); }');
   _restore_pos2(p);
}
 
/** 
 * Activate the Code Annotation tool window.  There was no similar command in
 * the official product as of 12.0.2.
 */
_command void activate_code_annotations()  name_info(','VSARG2_EDITORCTL)
{
   activate_toolbar("_tbannotations_browser_form","_type_list");
}
 
/** 
 * The parent command to some special cursor movements that fit my need.  I
 * have this command bound to Ctrl+Shift+']'.
 */
_command void kohei_move_cursor_special() name_info(',')
{
   if (_in_string()) {
      move_past_literal();
   } else {
      goto_begin_scope();
   }
}
 
/** 
 * When the cursor is somewhere on a function prototype, move the cursor to
 * the first character position after the opening brace.
 */
_command void goto_begin_scope() name_info(',')
{
   _UpdateContext(true, false, VS_UPDATEFLAG_context);
 
   int cxtid = tag_current_context();
 
   if (!cxtid) {
      // No usable context.  Bail out.
      return;
   }
 
   struct VS_TAG_BROWSE_INFO cm;
   tag_get_context_info(cxtid, cm);
   long cur_pos = _QROffset();
   long scope_begin = cm.scope_seekpos;
   if (cm.type_name :== 'func' && scope_begin > cur_pos) {
      _GoToROffset(cm.scope_seekpos);
   }
}
 
/** 
 * When the cursor is within a literal, move the cursor past that literal.
 */
_command void move_past_literal() name_info(',')
{
   if (_in_string()) {
      int status = _clex_find(STRING_CLEXFLAG, "N");
   }
}