slickedit highlight macro

//===========================================================================
// This module implements commands for highlighting all occurences of current
// word, selected text or regular expression with one of 7 predefined colors.
//
// 'highlight_textN' commands, where N is from 1 to 7, highlight all
// occurences of current word or selected text with color N. Selected text
// can not span more than current line. If cursor is on existing highlight
// then that highlight is cleared.
//
// 'highlight_reN' commands, where N is from 1 to 7, prompt user for a Perl
// regular expression and highlight all occurences with color N.
//
// 'highlight_text_clear_all' command clears all highlights created with
// 'highlight_textN' or 'highlight_reN' commands.
//
// Predefined colors are stored in 's_colors' array. You can change them
// to your taste.
//
// 'highlight_text_bind_keys' command binds 'highlight_textN', 'highlight_reN'
// and 'highlight_text_clear_all' commands all at once. Default bindings are
// Ctrl-1 to Ctrl-7, Ctrl-Shift-1 to Ctrl-Shift-7 and Ctrl-0 keys. Customize
// this command to your taste.
//
// By default searching for text to highlight is case-insensitive and not
// restricted to whole words. Two commands 'highlight_text_toggle_case_sensitive'
// and 'highlight_text_toggle_whole_word' toggle the flags.
//
// It is trivial to add more colors: add a color entry into 's_colors' and add
// new 'highlight_text'/'highlight_re' commands.
//===========================================================================

#pragma option (pedantic,on)

#include "slick.sh"
#include "markers.sh"

#import "seek.e"
#import "main.e"
#import "markfilt.e"
#import "mprompt.e"
#import "stdcmds.e"
#import "stdprocs.e"


//---------------------------------------------------------------------------
/**
 * Colors used for highlights. Each 'highlight_textN' command corresponds to
 * one of these colors. 'highlight_text1' uses color at index 0 and so on. You
 * may change or rearrange colors here. If you want more colors, just add a
 * color here and then add another 'highlight_text' and 'highlight_re' command
 * using one of existing as a template.
 */
static int s_colors[] = {
   0x0080FFFF, // yellow
   0x0080FF80, // green
   0x00FFFF80, // cyan
   0x00FFC080, // blue
   0x00FFA0FF, // magenta
   0x00A0A0FF, // rose
   0x0080C0FF  // gold
};




//---------------------------------------------------------------------------
/**
 * Holds information for highlighting with one color.
 */
struct HighlightInfo
{
   int markerType;   // separate marker type for easy removal of all markers with this color
   int colorId;      // color ID returned by _AllocColor()
   _str text;        // text to search for
   boolean useRegEx; // use or not regular expressions
};




//---------------------------------------------------------------------------
/**
 * Array for highlight information, one element per highlight color.
 *
 * This is a global variable, and as such it stays allocated and assigned even
 * if this module is reloaded. The module is reloaded often during development
 * and I don't want to exhaust editor's marker and color heaps, thus I
 * initialize this array only if it is empty.
 *
 * Note that when this module is unloaded manually with unload() command, the
 * global variables are removed completely and we probably get a resource leak.
 */
HighlightInfo g_highlightInfo[];
/**
 * Global variable controlling if searches for highlight strings are
 * case-sensitive. Toggled by 'highlight_text_toggle_case_sensitive' command.
 */
boolean g_highlightTextCaseSensitive = false;
/**
 * Global variable controlling if searches for highlight strings are looking for
 * whole words only. Toggled by 'highlight_text_toggle_whole_word' command.
 */
boolean g_highlightTextWholeWord = false;
/**
 * Global variable holding update timer ID. It is global so that we may stop old
 * timer when reloading this module during development.
 */
int g_highlightTextUpdateTimerId = -1;




//---------------------------------------------------------------------------
/**
 * Keeps last value of p_LastModified property to update highlights only if any
 * changes have been done to current buffer, including buffer switching.
 */
static int s_lastModified = 0;
/**
 * Keeps last regular expression entered. Used as a prompt for a new one.
 */
static _str s_lastRegEx;






//===========================================================================
// Commands
//===========================================================================

//---------------------------------------------------------------------------
/**
 * Binds 'highlight_textN', 'highlight_reN' and 'highlight_text_clear_all'
 * commands at once.
 *
 * Customize to your taste.
 */
_command void highlight_text_bind_keys() name_info (',')
{
   int tabIndex = find_index ('default_keys', EVENTTAB_TYPE);

   bindCommandToKey (tabIndex, 'highlight_text_clear_all', 'C-0');

   bindCommandToKey (tabIndex, 'highlight_text1', 'C-1');
   bindCommandToKey (tabIndex, 'highlight_text2', 'C-2');
   bindCommandToKey (tabIndex, 'highlight_text3', 'C-3');
   bindCommandToKey (tabIndex, 'highlight_text4', 'C-4');
   bindCommandToKey (tabIndex, 'highlight_text5', 'C-5');
   bindCommandToKey (tabIndex, 'highlight_text6', 'C-6');
   bindCommandToKey (tabIndex, 'highlight_text7', 'C-7');

   bindCommandToKey (tabIndex, 'highlight_re1', 'C-S-1');
   bindCommandToKey (tabIndex, 'highlight_re2', 'C-S-2');
   bindCommandToKey (tabIndex, 'highlight_re3', 'C-S-3');
   bindCommandToKey (tabIndex, 'highlight_re4', 'C-S-4');
   bindCommandToKey (tabIndex, 'highlight_re5', 'C-S-5');
   bindCommandToKey (tabIndex, 'highlight_re6', 'C-S-6');
   bindCommandToKey (tabIndex, 'highlight_re7', 'C-S-7');

   _config_modify_flags (CFGMODIFY_KEYS);
   save_config();
}

//---------------------------------------------------------------------------
static void bindCommandToKey (int tabIndex, _str commandName, _str keyName)
{
   int cmdIndex = find_index (commandName, COMMAND_TYPE);
   int keyIndex = event2index (name2event (keyName));

   if (!cmdIndex)
      say ('Command '''commandName''' not found');
   if (keyIndex < 0)
      say ('Invalid key '''keyName'''');

   if (cmdIndex && keyIndex >= 0)
      set_eventtab_index (tabIndex, keyIndex, cmdIndex);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 1.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text1() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (0);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 2.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text2() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (1);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 3.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text3() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (2);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 4.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text4() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (3);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 5.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text5() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (4);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 6.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text6() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (5);
}

//---------------------------------------------------------------------------
/**
 * Highlights all occurences of current word or selected text with color 7.
 * Selected text can not span more than current line. If cursor is on existing
 * highlight then that highlight is cleared.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_text7() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightCurrentText (6);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 1.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re1() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (0);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 2.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re2() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (1);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 3.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re3() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (2);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 4.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re4() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (3);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 5.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re5() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (4);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 6.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re6() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (5);
}

//---------------------------------------------------------------------------
/**
 * Prompts user for a regular expression and highlights all occurences with
 * color 7.
 *
 * Colors are hardcoded in 'highlight_text.e' module.
 */
_command void highlight_re7() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   highlightRegEx (6);
}

//---------------------------------------------------------------------------
/**
 * Clears all highlights created with 'highlight_textN' or 'highlight_reN'
 * commands.
 */
_command void highlight_text_clear_all() name_info (','VSARG2_READ_ONLY|VSARG2_REQUIRES_EDITORCTL|VSARG2_LINEHEX)
{
   stopTimer();

   int i;
   for (i = 0; i < g_highlightInfo._length(); ++i) {
      g_highlightInfo[i].text._makeempty();
      refreshHighlightInAllBuffers (i);
   }
}

//---------------------------------------------------------------------------
/**
 * Toggles 'g_highlightTextCaseSensitive' global variable that affects case
 * sensitivity of highlights searches.
 */
_command void highlight_text_toggle_case_sensitive() name_info (',')
{
   g_highlightTextCaseSensitive = !g_highlightTextCaseSensitive;

   int i;
   for (i = 0; i < g_highlightInfo._length(); ++i)
      refreshHighlightInAllBuffers (i);

   message ('Text highlights are now case-'(g_highlightTextCaseSensitive ? '' : 'in')'sensitive');
}

//---------------------------------------------------------------------------
/**
 * Toggles 'g_highlightTextCaseSensitive' global variable that affects case
 * sensitivity of highlights searches.
 */
_command void highlight_text_toggle_whole_word() name_info (',')
{
   g_highlightTextWholeWord = !g_highlightTextWholeWord;

   int i;
   for (i = 0; i < g_highlightInfo._length(); ++i)
      refreshHighlightInAllBuffers (i);

   message ('Text highlights now are '(g_highlightTextWholeWord ? '' : 'NOT ')'restricted to whole words');
}






//===========================================================================
// Implementation functions
//===========================================================================

//---------------------------------------------------------------------------
static void highlightCurrentText (int highlightIndex)
{
   if (!_isEditorCtl (false))
      return;

   // First check if cursor is on any of our highlight and turn it off if so
   int currHighlightIndex = getHighlightIndex();
   if (currHighlightIndex != -1) {
      g_highlightInfo[currHighlightIndex].text._makeempty();
      maybeStopTimer();
      refreshHighlightInAllBuffers (currHighlightIndex);
      return;
   }

   if (highlightIndex < 0 || highlightIndex >= g_highlightInfo._length())
      return;

   // Now highlight current word or selection if it is longer than 2 characters,
   // otherwise clear this highlight
   _str text = getWordOrSelection();
   if (text._length() < 2) {
      g_highlightInfo[highlightIndex].text._makeempty();
      maybeStopTimer();
   }
   else {
      g_highlightInfo[highlightIndex].text = text;
      g_highlightInfo[highlightIndex].useRegEx = false;
   }

   refreshHighlightInAllBuffers (highlightIndex);
}

//---------------------------------------------------------------------------
/**
 * Implementation of 'highlight_reN' commands. Prompts user for a regular
 * expression and highlights all occurences with color 'highlightIndex'.
 */
static void highlightRegEx (int highlightIndex)
{
   if (!_isEditorCtl (false))
      return;

   _str prompt = (s_lastRegEx._length() > 0 ? s_lastRegEx : getWordOrSelection());

   dlgResult := textBoxDialog (
      'Enter Perl regular expression to highlight',   // form caption
      0,                                              // flags
      1440 * 4,                                       // text box width
      'Perl regular expressions',                     // help item
      '',                                             // buttons and captions
      '',                                             // retrieve name
      'Expression:'prompt                             // prompt
   );

   if (dlgResult == COMMAND_CANCELLED_RC)
      return;

   _str text = strip (_param1);
   if (text._length() > 3) {
      s_lastRegEx = text;

      g_highlightInfo[highlightIndex].text = text;
      g_highlightInfo[highlightIndex].useRegEx = true;
      refreshHighlightInAllBuffers (highlightIndex);
   }
}

//---------------------------------------------------------------------------
/**
 * Searches for text stored in 'g_highlightInfo' array at 'highlightIndex' and
 * marks each match using corresponding color. If text is empty then just
 * removes particular highlight.
 */
static void refreshHighlight (int highlightIndex)
{
   if (highlightIndex < 0 || highlightIndex >= g_highlightInfo._length())
      return;

   _StreamMarkerRemoveType (p_window_id, g_highlightInfo[highlightIndex].markerType);

   if (g_highlightInfo[highlightIndex].text._isempty())
      return;

   if (g_highlightInfo[highlightIndex].colorId < 0)
      g_highlightInfo[highlightIndex].colorId = _AllocColor (/*fg*/ 0, /*bg*/s_colors[highlightIndex]);

   save_pos (auto savePos);
   save_search (auto s1, auto s2, auto s3, auto s4, auto s5);

   top();

   // Initialize search options
   _str options = '@>'; // no error msg, place cursor at end of string
   if (!g_highlightTextCaseSensitive)
      options :+= 'I';  // case insensitive
   if (g_highlightTextWholeWord)
      options :+= 'W';  // word search
   if (g_highlightInfo[highlightIndex].useRegEx)
      options :+= 'L';  // use Perl regex

   // Search for text and add a stream marker for each match
   int status = search (g_highlightInfo[highlightIndex].text, options);
   if (status != 0) {
      // Search string not found. If this is because invalid regular
      // expression is used then there is no need to keep it
      if (status == INVALID_REGULAR_EXPRESSION_RC) {
         message (get_message (INVALID_REGULAR_EXPRESSION_RC));
         g_highlightInfo[highlightIndex].text._makeempty();
         maybeStopTimer();
      }
   }
   else {
      // Got a match. Mark it and repeat
      do {
         int markerId = _StreamMarkerAdd (p_window_id, match_length ('S'), match_length(),
            /*real offset*/ false, 0, g_highlightInfo[highlightIndex].markerType, '');
         _StreamMarkerSetTextColor (markerId, g_highlightInfo[highlightIndex].colorId);
      } while (repeat_search (options) == 0);

      startTimer();
   }

   restore_search (s1, s2, s3, s4, s5);
   restore_pos (savePos);
}

//---------------------------------------------------------------------------
/**
 * Refreshes given highlight index in all buffers.
 */
static void refreshHighlightInAllBuffers (int highlightIndex)
{
   int currWindowId;
   save_view (currWindowId);

   int currBufId = p_buf_id;
   do {
      if ( !(p_buf_flags & VSBUFFLAG_HIDDEN))
         refreshHighlight (highlightIndex);
      _next_buffer ('HNR');
   } while (currBufId != p_buf_id);

   activate_window (currWindowId);
}

//---------------------------------------------------------------------------
/**
 * Starts update timer. The timer will be stopped when no more highlights are
 * left.
 */
static void startTimer()
{
   if (g_highlightTextUpdateTimerId < 0)
      g_highlightTextUpdateTimerId = _set_timer (500, updateHighlightsTimerProc);
}

//---------------------------------------------------------------------------
/**
 * Stops update timer.
 */
static void stopTimer()
{
   if (g_highlightTextUpdateTimerId >= 0) {
      _kill_timer (g_highlightTextUpdateTimerId);
      g_highlightTextUpdateTimerId = -1;
   }
}

//---------------------------------------------------------------------------
/**
 * Stops update timer if there are no highlights left.
 */
static void maybeStopTimer()
{
   int i;
   for (i = 0; i < g_highlightInfo._length(); ++i) {
      if (!g_highlightInfo[i].text._isempty())
         return;
   }
   stopTimer();
}

//---------------------------------------------------------------------------
/**
 * Refreshes all active highlights if editor is idle for more that 0.2 seconds
 * and current buffer has changed.
 */
static void updateHighlightsTimerProc()
{
   if (_no_child_windows() || _idle_time_elapsed() < 200)
      return;

   // Switch context to current MDI window
   int saveWId = p_window_id;
   p_window_id = _mdi.p_child;

   // Check if buffer has been modified since last update (p_LastModified is
   // incremented with each change)
   if (s_lastModified != p_LastModified) {
      s_lastModified = p_LastModified;

      // Refresh highlights
      int i;
      for (i = 0; i < g_highlightInfo._length(); ++i) {
         refreshHighlight (i);
      }
   }

   p_window_id = saveWId;
}

//---------------------------------------------------------------------------
/**
 * Returns index in 'g_highlightInfo' array if cursor is on text marked with one
 * of our highlights. Returns -1 if no highlight at cursor position.
 */
static int getHighlightIndex()
{
   int list[];
   int offset = _nrseek();
   int searchOffset = offset - p_col + 1; // search from the beginning of current line only
   int i;

   // Use _StreamMarkerFindList() to get a list of marks of specific (our) type
   // at cursor position. If list is not empty then cursor is on a mark
   for (i = 0; i < g_highlightInfo._length(); ++i) {
      _StreamMarkerFindList (list, p_window_id, offset, 1, searchOffset, g_highlightInfo[i].markerType);
      if (!list._isempty())
         return i;
   }
   return -1;
}

//---------------------------------------------------------------------------
/**
 * Returns a string containing current selection if selection is fully on the
 * current line or current word.
 */
static _str getWordOrSelection()
{
   if (select_active() && _select_type() != 'LINE' && _begin_select_compare() == 0 && _end_select_compare() == 0) {
      // CHAR or BLOCK selection begins and ends on current line
      int firstCol, lastCol, bufId;
      _get_selinfo (firstCol, lastCol, bufId);
      if (_select_type ('', 'I') || _select_type() == 'BLOCK')
         ++lastCol;  // inclusive selection

      //say ('firstCol='firstCol', lastCol='lastCol);
      return strip (_expand_tabsc (firstCol, lastCol - firstCol));
   }
   else
      return cur_word (0, '', true);
}

//---------------------------------------------------------------------------
_command void highlight_text_dump_debug_info() name_info (',')
{
   say ('--- highlight_text.e dump begin');
   int i;
   for (i = 0; i < g_highlightInfo._length(); ++i) {
      say (
         (i+1)": marker type=" g_highlightInfo[i].markerType :+
         ", colorId=" g_highlightInfo[i].colorId :+
         ", regex=" g_highlightInfo[i].useRegEx :+
         ", text='" (g_highlightInfo[i].text._isempty() ? '' : g_highlightInfo[i].text) "'"
      );
   }
   say ('g_highlightTextUpdateTimerId='g_highlightTextUpdateTimerId);
   say ('s_lastModified='s_lastModified', p_LastModified='p_LastModified);
   say ('--- highlight_text.e dump end');
}





//===========================================================================
// Module initialization
//===========================================================================

//---------------------------------------------------------------------------
definit()
{
   boolean firstTimeInit = g_highlightInfo._isempty();   // this is the very first time this module is loaded
   boolean haveHighlight = false;
   int i;

   // (Re)initialize g_highlightInfo array. For some reason SE gives runtime
   // errors during multifile search if colors are allocates and set here.
   // Therefore I deferred color initialization till the first use
   for (i = 0; i < s_colors._length(); ++i) {
      if (firstTimeInit) {
         g_highlightInfo[i].markerType = _MarkerTypeAlloc();   // allocating markers here seems safe
         _MarkerTypeSetFlags (g_highlightInfo[i].markerType, VSMARKERTYPEFLAG_AUTO_REMOVE);
         g_highlightInfo[i].colorId = -1;
      }
      if (g_highlightInfo[i].colorId >= 0) {
         _FreeColor (g_highlightInfo[i].colorId);
         g_highlightInfo[i].colorId = -1;
      }
      if (!g_highlightInfo[i].text._isempty())
         haveHighlight = true;
   }

   // Restart update timer if we already have any highlights. This may happen
   // during development if this module is reloaded. Our timer ID variable is
   // global, therefore we have a chance to stop the old timer first to avoid
   // a leak of timer IDs and "Invalid function pointer" error when old timer
   // tries to call nonexistent callback.
   //
   // Callback address can be made fixed by declaring callback globally, but it
   // is not necessary if we stop an old timer here
   if (haveHighlight) {
      stopTimer();
      startTimer();
   }
}


//
/**
 * Description: IDA-like Automatic Highlight for Slickedit 2007/2008
 * Copyright:   Megatops Software. 2007-11-1
 * Author:      Ding Zhaojie, zhaojie.ding@gmail.com
 *
 * ========================[  Revision History  ]=============================
 * Name             Date            Description
 * ---------------------------------------------------------------------------
 * Ding Zhaojie     2007-11-1       Initial version.
 * Ding Zhaojie     2009-1-26       Supports selection highlighting.
 */


#pragma option(strict, on)


/************************* [   INCLUDE FILES    ] ****************************/


#include 'slick.sh'


/************************* [ LOCAL DEFINITIONS  ] ****************************/


#define HL_TIMER    100
#define HL_DELAY    10


/************************* [    DECLARATIONS    ] ****************************/


/************************* [    PUBLIC DATA     ] ****************************/


/************************* [    PRIVATE DATA    ] ****************************/


static int timer = -1;


/************************* [ PRIVATE  FUNCTIONS ] ****************************/


static void
get_highlight_text(_str &text, _str &flag)
{
    typeless junk;
    if (select_active()) {
        int start_col = 0, end_col = 0, lines = 0;
        _get_selinfo(start_col, end_col, junk, '', junk, junk, junk, lines);
        if (_select_type('') != 'LINE' && lines == 1) {
            text = _expand_tabsc(start_col, end_col - start_col);
            flag = "";
            return;
        }
    }
    text = cur_word(junk);
    flag = "W";
}




static void
highlight_timer()
{
    static int  last_bufid;
    static _str last_word;


    if (_no_child_windows() || (_idle_time_elapsed() < HL_DELAY)) {
        return;
    }


    int orig_wid = p_window_id;
    p_window_id  = _mdi.p_child;
    _str cur_word, flag;
    get_highlight_text(cur_word, flag);


    /* check last highlight, prevent do the same highlighting twice */
    if (last_bufid == p_buf_id && cur_word == last_word) {
        p_window_id = orig_wid;
        return;
    }


    clear_highlights();
    if (cur_word != "") {
        typeless r1, r2, r3, r4, r5;
        save_search(r1, r2, r3, r4, r5);
        mark_all_occurences(cur_word, flag,
                            VSSEARCHRANGE_CURRENT_BUFFER, MFFIND_CURBUFFERONLY,
                            0, true, false, false);
        message("IDA-like Highlight: \"" cur_word "\"");
        restore_search(r1, r2, r3, r4, r5);
    }
    last_word  = cur_word;
    last_bufid = p_buf_id;
    refresh();
    p_window_id = orig_wid;
}




static void
start_module()
{
    if (timer < 0) {
        timer = _set_timer(HL_TIMER, highlight_timer);
        message("IDA-like Highlight Activated!");
    }
}




static void
end_module()
{
    if (timer >= 0) {
        _kill_timer(timer);
        timer = -1;
        clear_highlights();
        message("IDA-like Highlight Deactivated!");
    }
}


/************************* [  PUBLIC FUNCTIONS  ] ****************************/


_command void
ida_like_highlight() name_info(',')
{
    if (timer < 0) {
        start_module();
    } else {
        end_module();
    }
}




/* Kill ida_like_highlight if we load/unload the module */
void _on_load_module_ida_like_highlight(_str module)
{
    end_module();
}


void _on_unload_module_ida_like_highlight(_str module)
{
    end_module();
}


void _exit_ida_like_highlight()
{
    end_module();
}




definit()
{
    timer = -1;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值