Author Topic: auto-Comment loses tabs  (Read 7134 times)

dunkers

  • Senior Community Member
  • Posts: 606
  • Hero Points: 27
auto-Comment loses tabs
« on: August 23, 2007, 03:43:09 pm »
If one has a line such as this:

Code: [Select]
<tab>printf("Hello world\n");<tab>// My first line
and then one selects comment_line (or comment_toggle) then the line ends up like this:

Code: [Select]
//<spc><spc>printf("Hello world\n");<spc><spc><spc>// My first line
Now, if one reverses that with comment_erase the result is:

Code: [Select]
<tab>printf("Hello world\n");<spc><spc><spc>// My first line
The original tab has been replaced, but the tab between the end of the code and the real comment has been lost.

Incidentally, running beautify over the code restores the lost tabs, so it doesn't seem to be related to code formatting per se but the comment operation.

Sandra

  • SlickEdit Team Member
  • Senior Community Member
  • *
  • Posts: 754
  • Hero Points: 35
Re: auto-Comment loses tabs
« Reply #1 on: August 24, 2007, 01:42:52 pm »
Good catch!  You're correct in that it is a problem in comment-line.  I'll have a look at this today and see what I can come up with.

dunkers

  • Senior Community Member
  • Posts: 606
  • Hero Points: 27
Re: auto-Comment loses tabs
« Reply #2 on: August 24, 2007, 01:58:10 pm »
I have to say it was a colleague who noticed - I've been happily doing this for yonks without realising :)

Steve Black

  • Community Member
  • Posts: 57
  • Hero Points: 4
Re: auto-Comment loses tabs
« Reply #3 on: August 24, 2007, 06:34:14 pm »
comment-toggle???  You have a comment-togge???  Tell more.  I've been thinking I need to write that!

Sandra

  • SlickEdit Team Member
  • Senior Community Member
  • *
  • Posts: 754
  • Hero Points: 35
Re: auto-Comment loses tabs
« Reply #4 on: August 24, 2007, 06:40:45 pm »
Okay, I think I've got a solution for you.  This fix will be in v13, but I'll go ahead and tell you the lines to change to fix it now. 

Assuming you are running 12.0.3, then in box.e, change line 1270 from
Code: [Select]
new_line = s.comment_left :+ expand_tabs(line, substrStart);to
Code: [Select]
new_line = s.comment_left :+ expand_tabs(line, substrStart, -1, 'S');
and line 1283 should be changed from
Code: [Select]
new_line = expand_tabs(line, 1, leftmostcol - 1, 'S') :+ s.comment_left :+ expand_tabs(line, leftmostcol);to
Code: [Select]
new_line = expand_tabs(line, 1, leftmostcol - 1, 'S') :+ s.comment_left :+ expand_tabs(line, leftmostcol, -1, 'S');
If you're on a different version or if I haven't got the line numbers exactly right, you should be able to go to the file and search for the line using the unchanged code.  To find the exact command quickly type "fp comment" on the command line, which should take you right to box.e.

Hope this helps!  And out of curiosity, how long is a "yonk?"   ;)

Sandra

  • SlickEdit Team Member
  • Senior Community Member
  • *
  • Posts: 754
  • Hero Points: 35
Re: auto-Comment loses tabs
« Reply #5 on: August 24, 2007, 06:42:35 pm »
comment-toggle???  You have a comment-togge???  Tell more.  I've been thinking I need to write that!

HS2 solves all:
http://community.slickedit.com/index.php?topic=1789.0

dunkers

  • Senior Community Member
  • Posts: 606
  • Hero Points: 27
Re: auto-Comment loses tabs
« Reply #6 on: August 24, 2007, 08:28:58 pm »
@Sandra: Thanks for the quick fix! And the hint that 12.0.3 is around - I've only just got to 12.0.2  ;)

Er... yonks... good question. It means 'a long time' but I really have no idea where it comes from. One of those things I picked up from my folks yonks ago  ::)

http://www.worldwidewords.org/qa/qa-yon1.htm

@Steve: As Sandra notes, I nicked it from HS2 (along with some other mannerisms).

Steve Black

  • Community Member
  • Posts: 57
  • Hero Points: 4
Re: auto-Comment loses tabs
« Reply #7 on: August 25, 2007, 07:31:55 am »
@Sandra: Thanks (and to hs2 as well, of course).  That's very helpful.  I wonder how I missed it only a month ago.

dunkers

  • Senior Community Member
  • Posts: 606
  • Hero Points: 27
Re: auto-Comment loses tabs
« Reply #8 on: September 03, 2007, 01:09:10 pm »
@Sandra: I'm afraid that fix has a bug - the leading indent is changed to reflect the normal indent level, so if one is inside a function and there is <tab><tab> at the beginning of the line, after commenting/uncommenting the line is changed to have a single <tab>.

Sandra

  • SlickEdit Team Member
  • Senior Community Member
  • *
  • Posts: 754
  • Hero Points: 35
Re: auto-Comment loses tabs
« Reply #9 on: September 04, 2007, 04:27:40 pm »
I knew it was too easy the last time.   :)

The problem now appears to be inside comment-erase.  From your command line, run "fp comment-erase".  Then select that whole function (either with the mouse or using select-proc from the command line) and replace it with this new-fangled version.  Let me know if that fixes your problem (or breaks anything else).

Code: [Select]
/**
 * Uncomments currently selected lines or block using the
 * comment setup.  If there is no active selection, it
 * uncomments the current line.
 *
 * @return int 0 on success, 1 on failure.
 *
 * @appliesTo Edit_Window, Editor_Control
 *
 * @categories Edit_Window_Functions
 */
_command int comment_erase() name_info(','VSARG2_REQUIRES_EDITORCTL|VSARG2_MARK)
{
   BlockCommentSettings_t s;

   _str param='';
   _str ext='';
   _str orig_ext='';
   int status=0;

   typeless stype;
   boolean is_selection = true;
   _box_get_select_type(stype, is_selection);

   if ( arg()>1 ) {
      s.comment_left=arg(1);
      s.comment_right=arg(2);
   } else {
      parse arg(1) with param .;
      ext=param;
      orig_ext=ext;
      if ( ext=='' ) {
         typeless orig_ext_values;
         status=_EmbeddedStart(orig_ext_values,'');
         ext=p_extension;
         if ( status==1 ) _EmbeddedEnd(orig_ext_values);
         orig_ext=ext;
      }
      if ( ext!='' ) {
         BlockCommentSettings_t temp:[];

         if ( getCommentSettings(ext,temp,'L') ) {
            _message_box('There is currently no comment setup information for 'orig_ext);
            return(1);
         }
         s=temp:[ext];
      } else {
         _message_box('There is currently no comment setup information for 'orig_ext);
         return(1);
      }
   }
   if ( s.comment_left=='' && s.comment_right=='' ) {
      _message_box('There is currently no comment setup information for 'orig_ext);
      return(1);
   }
   if (p_xlat) {
      s.comment_left=_UTF8ToMultiByte(s.comment_left);
      s.comment_right=_UTF8ToMultiByte(s.comment_right);
   }

   _undo('S');   // So we can quickly undo if a problem
   int width=0;
   int start_col=0;
   int end_col=0;
   typeless p;
   save_pos(p);
   if (!is_selection) {
      select_line();
   }

   if ( stype=='LINE' ) {
      width=longest_line_in_selection_raw();
      start_col=1;
      end_col=width;
   } else if ( stype=='BLOCK' ) {
      int dummy=0;
      _get_selinfo(start_col,end_col,dummy);
      width=end_col - start_col + 1;
   } else {
      // stype=='CHAR'
      _select_type('','L','LINE');
      width=longest_line_in_selection_raw();
      start_col=1;end_col=width;
      stype='LINE';
   }

   _begin_select();

   _str line='';
   _str before='';
   _str middle='';
   _str after='';
   _str indent='';
   _str cmtLeft = '';
   _str cmtRight = '';
   int midlen = 0;
   int size_left_comment = 0;
   int leftmostcol = 0;
   int nonblank_col=0;
   int lcPos = 0;
   int rcPos = 0;
   int i=0;
   status=0;
   boolean first_line_erase = true;    // keep track of first line we erase
   boolean first_line_indent = true;   // keep track of first line we reindent (in case of blank lines)
   boolean add_back_spaces = false;    // whether to add back spaces to replace comment chars
   int adj = 0;
   for ( ;; ) {
      get_line_raw(line);

      // find comment characters in lines
      _str ss =_escape_re_chars(s.comment_left):+'(?@|$)';
      if ( s.comment_right!="" ) {
         ss=ss:+_escape_re_chars(s.comment_right);
      }
      // line commenting with either LEFT_MARGIN OR LEVEL_INDENT modes
      if ( s.comment_col == 0 && stype == 'LINE' ) {
         
         // special case for first line - must determine which commenting style we are using.
         if (first_line_erase) {
            // make sure we're in a comment
            first_non_blank();
            if (!_in_comment()) {
               status = 1;
               break;
            }

            cmtLeft = s.comment_left;
            cmtRight = s.comment_right;
            lcPos = IsCommentWellFormed(line, cmtLeft, cmtRight);

            if (!lcPos) {
               status = 1;
               break;
            }
            size_left_comment = length(cmtLeft);
               
            // decide if we need to add back spaces that were deleted in
            // uncommenting
            if (s.mode == LEFT_MARGIN) {
               // find the leftmost non-comment and subtract, this will be the
               // leftmost column after we erase the comments
               leftmostcol=_leftmost_col_in_selection_after_start(lcPos + size_left_comment);
               leftmostcol -= size_left_comment;
               if (leftmostcol > 1 || !(size_left_comment % p_SyntaxIndent)) {
                  add_back_spaces = true;
               }
            }
           
            first_line_erase = false;
         } else {
            // make sure this is a well-formed comment - has comment characters in same column on every line
            // this case should be caught in IsCommentWellFormed -
            if (!strieq(cmtLeft, expand_tabs(line, lcPos, size_left_comment, 'S'))) {
               status = 1;
               break;
            }
         }

         before = imaginary_substr(line, 1, lcPos - 1, 'W');

         // add the spaces back if they were deleted
         if (add_back_spaces) {

            // take a substring up to the left comment
            _str begin = substr(line, 1, lcPos + size_left_comment - 1);
            _str last = substr(line, lcPos + size_left_comment);

            // we can carelessly just toss spaces in because we're going to fix indent later
            line = begin :+ substr('', 1, size_left_comment) :+ last;
         }

         // check for right comment
         rcPos = 0;
         if (cmtRight != "") {
            ss = _escape_re_chars(cmtRight);
            rcPos = lastpos('{#0'ss'}', expand_tabs(line), '', p_rawpos'er');
         }
         
         // there is a right comment, but not for long!
         if (rcPos) {
            midlen = rcPos - (lcPos + size_left_comment);
            middle = imaginary_substr(line, lcPos + size_left_comment, midlen, 'B');
            after = imaginary_substr(line, rcPos + length(cmtRight));
         } else {
            // no right comment, just take rest of line
            middle = imaginary_substr(line, lcPos + size_left_comment);
            after = "";
         }

         line = before :+ middle :+ after;
         line = strip(line, 'T');
         replace_line_raw(line);

         // if this is the first non-blank line in the selection, reindent it and save the adjustment
         if (first_line_indent) {

            // check for a blank line - we don't want to reindent based on a blank line
            nonblank_col = pos('[~ \t]', expand_tabs(line), 1, p_rawpos'er');
            if (nonblank_col) {

               // if the first character is another comment, do not reindent
               first_non_blank();
               if (!_in_comment()) {
                  // what is the current level of indent for this line?
                  int ind = find_new_column();
                  if (ind > 0) {
                     adj = ind - nonblank_col;
                  } else {
                     // if there is no callback for indent_col, we assume the comments were made in
                     // SlickEdit and adjust according to the indent level
                     // note that this method does not account for shifting.
                     // no adjustment for level of indent mode
                     // +(size_left_comment) adjustment for left margin
                     if (s.mode == LEFT_MARGIN) {
                        adj = size_left_comment;
                     }
                  }
               }
               first_line_indent = false;     
            }
         }
       
         // adjust all lines as according to first line
         line = ReindentLine(line, adj);
         replace_line_raw(line);

      } else {             // we have a comment col or a block comment in this case
         lcPos = pos('{#0'ss'}', expand_tabs(line), 1, p_rawpos'er');
         if (!lcPos) {
            status = 1;
            break;
         }

         size_left_comment = length(s.comment_left);
         before = expand_tabs(line, 1, pos('S0') - 1, 'S');

         // check for right comment
         if (s.comment_right != "") {
            ss = _escape_re_chars(s.comment_right);
            rcPos = lastpos('{#0'ss'}', expand_tabs(line), '', p_rawpos'er');
         }
         
         // there is a right comment, but not for long!
         if (rcPos) {
            midlen = rcPos - (lcPos + size_left_comment);
            middle = imaginary_substr(line, lcPos + size_left_comment, midlen, 'B');
            after = imaginary_substr(line, rcPos + length(s.comment_right));
         } else {
            // no right comment, just take rest of line
            middle = imaginary_substr(line, lcPos + size_left_comment);
            after = "";
         }

         line = before :+ middle :+ after;
         line = strip(line, 'T');

         // preserve tabs
         nonblank_col = pos('[~ \t]', line, 1, p_rawpos'er');
         if (nonblank_col > 1) {
            line = substr(line, nonblank_col);
            // add back size_left_comment so that we don't move the code any
            // (only if not in BLOCK mode, since BLOCK inserts, not
            // overwrites)
            if (stype == 'BLOCK') {
               indent = indent_string(nonblank_col - 1);
            } else {
               indent = indent_string(nonblank_col - 1 + size_left_comment);
            }
            line = indent :+ line;
         }

         replace_line_raw(line);
      }

      ++i;
      if ( _end_select_compare()>=0 ) break;
      status=down();
      if ( status ) break;
   }
   if ( status ) {
      _message_box('Cannot remove comment characters.  Unrecognized or inconsistent commenting approach has been found.');
      _undo();
      if (!is_selection) {
         deselect();
      }
      return(1);
   }

   _begin_select();_deselect();
   if ( stype=='LINE' ) {
      _select_line();
      if ( i ) down(i-1);
      _select_line();
      _begin_select();
      p_col=1;
   } else {
      // stype=='BLOCK'
      _select_block();
      if ( i ) down(i-1);
      /* +width for width of block selection
       * -length(comment_left) for length of left-side comment chars
       * -length(comment_right) for length of right-side comment chars
       * -2 for the space on either side of boxed line
       */
      p_col+=width-length(s.comment_left)-length(s.comment_right)-2-1;_select_block();
      _begin_select();
   }

   if (!is_selection) {
      deselect();
   }
   return(0);
}

dunkers

  • Senior Community Member
  • Posts: 606
  • Hero Points: 27
Re: auto-Comment loses tabs
« Reply #10 on: September 04, 2007, 06:32:12 pm »
Seems to be something of a problem there, Sandra: leftmost_col_in_selection_after_start() doesn't exist anywhere.

Er.. this is still 12.0.2 since I haven't had a chance to upgrade yet. Could this be a new function in 12.0.3? My colleague is on 12.0.3 (and he's the one that creates these problems anyway) so I'll get him to check it out tomorrow.


Sandra

  • SlickEdit Team Member
  • Senior Community Member
  • *
  • Posts: 754
  • Hero Points: 35
Re: auto-Comment loses tabs
« Reply #11 on: September 04, 2007, 06:51:26 pm »
I think that function was new to 12.0.3.  In case you don't get a chance to talk to your colleague, here it is (simply add it to box.e and reload that module):

Code: [Select]
/**
 * Finds the leftmost column in a selection, checking columns
 * only after the designated start column.  Note that this will
 * search for the first NONBLANK column.  So if a line that is
 * blank after the start column is found, that line is essentially
 * thrown out and not considered.
 *
 * @param start
 * @param markid
 *
 * @return int
 */
static int _leftmost_col_in_selection_after_start(int start = 1, _str markid='')
{
   if ( !select_active() ) {
      _message_box('No selection active');
      return(MAX_LINE);
   }
   save_pos(auto p);
   int end_col=0;
   int throw_out_last_line=0;
   if ( _select_type()=='CHAR' ) {
      typeless dummy;
      _get_selinfo(dummy,end_col,dummy);
      if ( end_col==1 ) {
         // Throw out the last line of the character selection
         throw_out_last_line=1;
      }
   }
   int status=_begin_select(markid);
   if ( status ) return(MAX_LINE);

   int leftmostcol = pos('[~ \t]', _expand_tabsc(), start, p_rawpos'er');
   if (leftmostcol == 0) {
      leftmostcol = MAX_LINE;
   }

   for ( ;; ) {
      if ( down() ||
           _end_select_compare(markid)>0 ||
           (throw_out_last_line && !_end_select_compare(markid)) ) {
         break;
      }
      int col = pos('[~ \t]', _expand_tabsc(), start, p_rawpos'er');
      if ( col > 0 && col < leftmostcol ) {
         leftmostcol=col;
      }
   }
   restore_pos(p);
   return(leftmostcol);
}

dunkers

  • Senior Community Member
  • Posts: 606
  • Hero Points: 27
Re: auto-Comment loses tabs
« Reply #12 on: September 05, 2007, 11:19:46 am »
Thanks for the extra code. Unfortunately I ran into yet another missing function (actually two!). Looks like you'd be giving me 12.0.3 in message sized chunks, so it makes more sense to upgrade and be done with it :)

Meantime, I set my colleague onto this and he says that it seems to be sorted now. Great stuff, thanks  ;D