Loading ...
Sorry, an error occurred while loading the content.
 

Smart use of

Expand Messages
  • A. S. Budden
    Dear all, I ve recently started using the CleverTab function below, modified from the bottom of the comments page on tip 102. This is brilliant from my point
    Message 1 of 6 , Oct 27 8:46 AM
      Dear all,

      I've recently started using the CleverTab function below, modified from
      the bottom of the comments page on tip 102. This is brilliant from my
      point of view:

      - tab produces tabs at the start of the line for indenting*;
      - tab shows the longest unique option in the omnicomplete list
      when using omnicompletion;
      - tab cycles through the list of completions if the popup menu is
      visible but omnicompletion isn't used;
      - otherwise, it returns a tab.

      What I'd like to do is change the last one of those so that it puts in
      enough spaces to reach the next tabstop so that good formatting is
      maintained regardless of the tabstop setting on a users editor.

      However, I can't figure out how to achieve this.

      The 'expandtab' option is no use as it will change the tabs at the start
      of the line (used for indentation) to spaces, which will result in a
      really badly formatted piece of source code (as it is edited by several
      people who all like different tab stops)*. Similarly, replacing "\<Tab>"
      in the last return line with " " is no use as it will always insert
      four spaces, even if we're halfway through a tab stop (it's also not
      very flexible for different tabstop settings).

      Can anyone offer any suggestions for this?

      Cheers,

      Al

      function! CleverTab()
      " If we've only had spaces/tabs thus far, add a tab
      if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$'
      return "\<Tab>"
      " If we're omnifuncing, act on it
      elseif exists('&omnifunc') && &omnifunc != ''
      return "\<C-X>\<C-O>"
      elseif pumvisible()
      return "\<C-N>"
      else
      " This should ideally be 'spaced tab'
      return "\<Tab>"
      endif
      endfunction


      * If anyone wants to try to preach about the soft tabs vs. hard tabs,
      please do it elsewhere. Having worked on a lot of collaborative
      projects, I have found that, for me, hard tabs for indentation and
      soft ones elsewhere is by far the best way of maintaining consistent
      and neat code. If you disagree, that's fine by me, to each their own,
      but please keep it to yourself and spare us all the pointless rants.
    • Benji Fisher
      ... [snip] The expandtab option does not affect existing tabs in the file (unless you :retab) so it should be safe to have your function reset/set it
      Message 2 of 6 , Oct 27 10:45 AM
        On Fri, Oct 27, 2006 at 04:46:02PM +0100, A. S. Budden wrote:
        > Dear all,
        >
        > I've recently started using the CleverTab function below, modified from
        > the bottom of the comments page on tip 102. This is brilliant from my
        > point of view:
        >
        > - tab produces tabs at the start of the line for indenting*;
        > - tab shows the longest unique option in the omnicomplete list
        > when using omnicompletion;
        > - tab cycles through the list of completions if the popup menu is
        > visible but omnicompletion isn't used;
        > - otherwise, it returns a tab.
        >
        > What I'd like to do is change the last one of those so that it puts in
        > enough spaces to reach the next tabstop so that good formatting is
        > maintained regardless of the tabstop setting on a users editor.
        >
        > However, I can't figure out how to achieve this.
        >
        > The 'expandtab' option is no use as it will change the tabs at the start
        > of the line (used for indentation) to spaces, which will result in a
        > really badly formatted piece of source code (as it is edited by several
        > people who all like different tab stops)*. Similarly, replacing "\<Tab>"
        > in the last return line with " " is no use as it will always insert
        > four spaces, even if we're halfway through a tab stop (it's also not
        > very flexible for different tabstop settings).
        >
        > Can anyone offer any suggestions for this?
        [snip]

        The 'expandtab' option does not affect existing tabs in the file
        (unless you :retab) so it should be safe to have your function reset/set
        it depending on whether you are at the start of the line or not. I have
        not tested this.

        For another approach, pretty much what you suggested, look at the
        VarTab() function in foo.vim, my file of example vim functions:
        http://www.vim.org/script.php?script_id=72
        This function returns a calculated number of spaces, and it should be
        pretty easy to use the same idea for your function. (It just takes a
        little :while loop.)

        HTH --Benji Fisher
      • A. S. Budden
        ... Many thanks for your help Benji, both suggestions look useful. I ve been playing around with the first option (as the code _should_ be a bit neater I
        Message 3 of 6 , Oct 31 5:17 AM
          On 27/10/06, Benji Fisher <benji@...> wrote:
          > On Fri, Oct 27, 2006 at 04:46:02PM +0100, A. S. Budden wrote:
          > > Dear all,
          > >
          > > I've recently started using the CleverTab function below, modified from
          > > the bottom of the comments page on tip 102. This is brilliant from my
          > > point of view:
          > >
          > > - tab produces tabs at the start of the line for indenting*;
          > > - tab shows the longest unique option in the omnicomplete list
          > > when using omnicompletion;
          > > - tab cycles through the list of completions if the popup menu is
          > > visible but omnicompletion isn't used;
          > > - otherwise, it returns a tab.
          > >
          > > What I'd like to do is change the last one of those so that it puts in
          > > enough spaces to reach the next tabstop so that good formatting is
          > > maintained regardless of the tabstop setting on a users editor.
          > >
          > > However, I can't figure out how to achieve this.
          > >
          > > The 'expandtab' option is no use as it will change the tabs at the start
          > > of the line (used for indentation) to spaces, which will result in a
          > > really badly formatted piece of source code (as it is edited by several
          > > people who all like different tab stops)*. Similarly, replacing "\<Tab>"
          > > in the last return line with " " is no use as it will always insert
          > > four spaces, even if we're halfway through a tab stop (it's also not
          > > very flexible for different tabstop settings).
          > >
          > > Can anyone offer any suggestions for this?
          > [snip]
          >
          > The 'expandtab' option does not affect existing tabs in the file
          > (unless you :retab) so it should be safe to have your function reset/set
          > it depending on whether you are at the start of the line or not. I have
          > not tested this.

          Many thanks for your help Benji, both suggestions look useful. I've
          been playing around with the first option (as the code _should_ be a bit
          neater I think), but I'd quite like to ensure that expandtab is left off
          at the end of the insertion (as I'd like to be able to enable and
          disable use of CleverTab).

          The problem with this is that inside one of the 'if/elseif/else' blocks,
          I need to set expandtab, print something into the insert buffer and then
          reset expandtab. I'm struggling with this, despite having played around
          with lots of possibilities and done what I feel is a fairly
          comprehensive trawl of the documentation.

          What I've tried:

          ---
          let &expandtab = 1
          return "\<Tab>"
          let &expandtab = 0 " Never gets executed
          ---
          let &expandtab = 1
          feedkeys("\<Tab>", 'n') " Gets executed AFTER the return
          let &expandtab = 0
          return ""
          ---

          I've also tried a simple one with the first two lines of the first
          example, combined with:

          inoremap <Tab> <C-R>=CleverTab()<CR><C-O>:set noet<CR>

          This one works fine for the start of line and mid-line examples, but on
          the omnifunc version (see updated CleverTab below), it fails as the
          <C-O> just breaks it out of the menu (which I don't want) and the
          mapping then prints ":set noet" to the buffer.

          Is there a way to do the equivalent of feedkeys, but without it waiting
          for mappings to be completed? Alternatively, can you suggest a
          different way of using expandtab?

          If not, then I'll look into the while loop approach I guess.

          Many thanks again for your help,

          Al

          " A clever tab function
          function! CleverTab()
          " If we've only had spaces/tabs thus far, add a tab
          if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$'
          " This is the simple case"
          return "\<Tab>"
          " If last character was a space, use spaces
          elseif getline('.')[col(".")-2] =~ ' '
          let &expandtab = 1
          call feedkeys("\<Tab>", 'n') " This gets executed too late
          let &expandtab = 0
          return ""
          " If we're omnifuncing, act on it
          elseif exists('&omnifunc') && &omnifunc != ''
          " This causes problems if noet is set in a mapping
          return "\<C-X>\<C-O>"
          elseif pumvisible()
          " This probably does too, but I haven't tested it yet
          return "\<C-N>"
          else
          " This should ideally be 'spaced tab'
          let &expandtab = 1
          return "\<Tab>"
          let &expandtab = 0 " This never gets executed
          endif
          endfunction
        • A. S. Budden
          ... Ah! I d tried it without the before the and it hadn t worked (forgot to mention it earlier!), but hadn t thought to escape it. Thanks for that.
          Message 4 of 6 , Oct 31 7:57 AM
            On 31/10/06, Yakov Lerner <iler.ml@...> wrote:
            > On 10/31/06, A. S. Budden <abudden@...> wrote:
            > > On 27/10/06, Benji Fisher <benji@...> wrote:
            > > > On Fri, Oct 27, 2006 at 04:46:02PM +0100, A. S. Budden wrote:
            > > > > Dear all,
            > > > >
            > > > > I've recently started using the CleverTab function below, modified from
            > > > > the bottom of the comments page on tip 102. This is brilliant from my
            > > > > point of view:
            > > > >
            > > > > - tab produces tabs at the start of the line for indenting*;
            > > > > - tab shows the longest unique option in the omnicomplete list
            > > > > when using omnicompletion;
            > > > > - tab cycles through the list of completions if the popup menu is
            > > > > visible but omnicompletion isn't used;
            > > > > - otherwise, it returns a tab.
            > > > >
            > > > > What I'd like to do is change the last one of those so that it puts in
            > > > > enough spaces to reach the next tabstop so that good formatting is
            > > > > maintained regardless of the tabstop setting on a users editor.
            > > > >
            > > > > However, I can't figure out how to achieve this.
            > > > >
            > > > > The 'expandtab' option is no use as it will change the tabs at the start
            > > > > of the line (used for indentation) to spaces, which will result in a
            > > > > really badly formatted piece of source code (as it is edited by several
            > > > > people who all like different tab stops)*. Similarly, replacing "\<Tab>"
            > > > > in the last return line with " " is no use as it will always insert
            > > > > four spaces, even if we're halfway through a tab stop (it's also not
            > > > > very flexible for different tabstop settings).
            > > > >
            > > > > Can anyone offer any suggestions for this?
            > > > [snip]
            > > >
            > > > The 'expandtab' option does not affect existing tabs in the file
            > > > (unless you :retab) so it should be safe to have your function reset/set
            > > > it depending on whether you are at the start of the line or not. I have
            > > > not tested this.
            > >
            > > Many thanks for your help Benji, both suggestions look useful. I've
            > > been playing around with the first option (as the code _should_ be a bit
            > > neater I think), but I'd quite like to ensure that expandtab is left off
            > > at the end of the insertion (as I'd like to be able to enable and
            > > disable use of CleverTab).
            > >
            > > The problem with this is that inside one of the 'if/elseif/else' blocks,
            > > I need to set expandtab, print something into the insert buffer and then
            > > reset expandtab. I'm struggling with this, despite having played around
            > > with lots of possibilities and done what I feel is a fairly
            > > comprehensive trawl of the documentation.
            > >
            > > What I've tried:
            > >
            > > ---
            > > let &expandtab = 1
            > > return "\<Tab>"
            > > let &expandtab = 0 " Never gets executed
            > > ---
            > > let &expandtab = 1
            > > feedkeys("\<Tab>", 'n') " Gets executed AFTER the return
            > > let &expandtab = 0
            > > return ""
            >
            > Try this:
            >
            > set &expandtab = 1
            > call feedkeys("\<Tab>\<C-O>:set noet\n", 'n')

            Ah!

            I'd tried it without the "\" before the <C-O> and it hadn't worked
            (forgot to mention it earlier!), but hadn't thought to escape it.
            Thanks for that.

            Ok, that leads me on to the next question (and I suspect that this is
            slightly more challenging). I've made a couple of changes to the
            CleverTab script such that the first test looks for "^\t*$" instead of
            \s and such that the test for a space now looks for "\A" (i.e. only
            using omnifunc if after likely object name). This is working really
            well, but falls down in the following situation:

            I type (underscore substituted for space; <AI-*> to indicate vim's
            autoindenting and <-*> is a TAB):

            if_(x_==_1)
            {
            <AI---->x_=_1;<><------>//_This_is_a_comment<ENTER>
            <AI---->_<-----><------>//_that_continues<ENTER>
            <AI-------------------->//_onto_the_following_lines
            <A FEW BACKSPACES>
            }

            I get:

            if_(x_==_1)
            {
            <------>x_=_1;__________//_This_is_a_comment
            <------>________________//_that_continues
            <------><------><------>//_onto_the_following_lines
            }

            The third line should be:
            <------>________________//_onto_the_following_lines

            Did that make sense?

            The key problem here is that the autoindenting is, rather
            understandably, using tabs to achieve the indent, but if another
            developer works on the code with ts set to something different, the
            comment on the third line won't line up.

            Has anyone got any suggestions or am I asking too much from my editor?!

            Cheers,

            Al
          • Benji Fisher
            On Tue, Oct 31, 2006 at 03:57:18PM +0000, A. S. Budden wrote: [snip] ... HTH --Benji Fisher
            Message 5 of 6 , Nov 1, 2006
              On Tue, Oct 31, 2006 at 03:57:18PM +0000, A. S. Budden wrote:
              [snip]
              > The key problem here is that the autoindenting is, rather
              > understandably, using tabs to achieve the indent, but if another
              > developer works on the code with ts set to something different, the
              > comment on the third line won't line up.
              >
              > Has anyone got any suggestions or am I asking too much from my editor?!

              :help 'preserveindent'
              :help 'copyindent'

              HTH --Benji Fisher
            • A. S. Budden
              ... Brilliant, thank you! Al
              Message 6 of 6 , Nov 1, 2006
                On 01/11/06, Benji Fisher <benji@...> wrote:
                > On Tue, Oct 31, 2006 at 03:57:18PM +0000, A. S. Budden wrote:
                > [snip]
                > > The key problem here is that the autoindenting is, rather
                > > understandably, using tabs to achieve the indent, but if another
                > > developer works on the code with ts set to something different, the
                > > comment on the third line won't line up.
                > >
                > > Has anyone got any suggestions or am I asking too much from my editor?!
                >
                > :help 'preserveindent'
                > :help 'copyindent'

                Brilliant, thank you!

                Al
              Your message has been successfully submitted and would be delivered to recipients shortly.