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

Re: Operator pending mode

Expand Messages
  • Ben Schmidt
    ... Here s a somewhat naively implemented example where a custom text-object is defined that allows you to operate on a function name whether the cursor is on
    Message 1 of 26 , Oct 30, 2007
    • 0 Attachment
      > Well, I can see that you get the information, but this is not really a
      > useful real-world example. Think of a user that wants to get something
      > done for which v:operator is needed. And for which there is no other
      > solution.

      Here's a somewhat naively implemented example where a custom text-object is
      defined that allows you to operate on a function name whether the cursor is on the
      name itself or on its arguments. You can yank with yF, change with cF, uppercase
      with gUF, etc. I can't think of any other way to do this, or more complicated
      language-based custom text-object definition--e.g. yank/change a whole conjunction
      or disjunction in a logic language, yank or change the condition of an 'if' or
      'while' loop from anywhere within its body. Some of these would be more useful
      than others, of course, but there are a lot of real world possibilities, I think.

      Ben.



      :onoremap F <Esc>:call OperateFunctionName()<CR>
      function! OperateFunctionName()
      let last_count = v:count
      let last_op = v:operator
      let last_reg = v:register
      exe "normal \<Esc>"
      while search('\(\%#\i\|\i\s*\%#\)\i*\s*(','ce',line('.')+1) == 0
      normal [(
      endwhile
      exe "normal \<BS>\"_yiw"
      echo 'normal '.(last_count>0?(last_count):'').'"'.last_reg.last_op.'e'
      endfun





      Send instant messages to your online friends http://au.messenger.yahoo.com


      --~--~---------~--~----~------------~-------~--~----~
      You received this message from the "vim_use" maillist.
      For more information, visit http://www.vim.org/maillist.php
      -~----------~----~----~----~------~----~------~--~---
    • Ben Schmidt
      ... Send instant messages to your online friends http://au.messenger.yahoo.com --~--~---------~--~----~------------~-------~--~----~ You received this message
      Message 2 of 26 , Oct 30, 2007
      • 0 Attachment
        >> Well, I can see that you get the information, but this is not really a
        >> useful real-world example. Think of a user that wants to get something
        >> done for which v:operator is needed. And for which there is no other
        >> solution.
        >
        > Here's a somewhat naively implemented example where a custom text-object is
        > defined that allows you to operate on a function name whether the cursor is on the
        > name itself or on its arguments. You can yank with yF, change with cF, uppercase
        > with gUF, etc. I can't think of any other way to do this, or more complicated
        > language-based custom text-object definition--e.g. yank/change a whole conjunction
        > or disjunction in a logic language, yank or change the condition of an 'if' or
        > 'while' loop from anywhere within its body. Some of these would be more useful
        > than others, of course, but there are a lot of real world possibilities, I think.

        A better one:

        :onoremap F <Esc>:call OperateFunctionName()<CR>
        :function! OperateFunctionName()
        : let save_count = v:count
        : let save_op = v:operator
        : let save_reg = v:register
        : while search('\(\%#\i\|\i\s*\%#\)\i*\s*(','ce',line('.')+1) == 0
        : if searchpair('(','',')','bW') == 0
        : normal "\<Esc>"
        : return
        : endif
        : endwhile
        : exe "normal \<BS>\"_yiw"
        : exe 'normal "'.save_reg.(save_count>0?(save_count):'').save_op.'e'
        :endfun





        Send instant messages to your online friends http://au.messenger.yahoo.com


        --~--~---------~--~----~------------~-------~--~----~
        You received this message from the "vim_use" maillist.
        For more information, visit http://www.vim.org/maillist.php
        -~----------~----~----~----~------~----~------~--~---
      • Ben Schmidt
        [CCing this to the mailing lists; only went to Bram before, but some parts may be useful for others.] ... Very happy to modify the patch to document this. It
        Message 3 of 26 , Oct 30, 2007
        • 0 Attachment
          [CCing this to the mailing lists; only went to Bram before, but some parts may be
          useful for others.]

          > I'm not quite convinced adding v:operator is useful. What would help is
          > giving a couple of examples how it's used. Also, in the docs for
          > v:operator it would be good to have a few examples of the values. I
          > suppose it can be one char, like "d", but also something longer. How
          > about the count, e.g., when I do "4d"?

          Very happy to modify the patch to document this. It does not include the count;
          that is what v:count is for. And it will be two characters for commands that begin
          with 'g' or 'z', and one character otherwise.

          Happy to include an example or two as well. I emailed a candidate a few moments
          ago. Interested to hear what people think, and will do so before revising the
          patch. My gut feeling regarding this, though, would be that if people want to use
          this, they will know how they want to use it, so an example isn't really necessary
          and would probably add more clutter to the docs than insight. Still, as I said,
          I'm very happy to put one in the patch!

          Ben.





          Send instant messages to your online friends http://au.messenger.yahoo.com


          --~--~---------~--~----~------------~-------~--~----~
          You received this message from the "vim_use" maillist.
          For more information, visit http://www.vim.org/maillist.php
          -~----------~----~----~----~------~----~------~--~---
        • Bram Moolenaar
          ... I see. In general the reason we need v:operator would then be that you need it for situations where you need to get out of operator pending mode, move
          Message 4 of 26 , Oct 31, 2007
          • 0 Attachment
            Ben Schmidt wrote:

            > > Well, I can see that you get the information, but this is not really a
            > > useful real-world example. Think of a user that wants to get something
            > > done for which v:operator is needed. And for which there is no other
            > > solution.
            >
            > Here's a somewhat naively implemented example where a custom
            > text-object is defined that allows you to operate on a function name
            > whether the cursor is on the name itself or on its arguments. You can
            > yank with yF, change with cF, uppercase with gUF, etc. I can't think
            > of any other way to do this, or more complicated language-based custom
            > text-object definition--e.g. yank/change a whole conjunction or
            > disjunction in a logic language, yank or change the condition of an
            > 'if' or 'while' loop from anywhere within its body. Some of these
            > would be more useful than others, of course, but there are a lot of
            > real world possibilities, I think.
            >
            > Ben.
            >
            >
            > :onoremap F <Esc>:call OperateFunctionName()<CR>
            > function! OperateFunctionName()
            > let last_count = v:count
            > let last_op = v:operator
            > let last_reg = v:register
            > exe "normal \<Esc>"
            > while search('\(\%#\i\|\i\s*\%#\)\i*\s*(','ce',line('.')+1) == 0
            > normal [(
            > endwhile
            > exe "normal \<BS>\"_yiw"
            > echo 'normal '.(last_count>0?(last_count):'').'"'.last_reg.last_op.'e'
            > endfun

            I see. In general the reason we need v:operator would then be that you
            need it for situations where you need to get out of operator pending
            mode, move around and restart the operator.

            Did you copy the v:variable values because they change when executing
            the other commands? A remark about that will be useful in the docs.

            OK, I'll include the patch after sufficient testing.

            --
            hundred-and-one symptoms of being an internet addict:
            70. ISDN lines are added to your house on a hourly basis

            /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
            /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
            \\\ download, build and distribute -- http://www.A-A-P.org ///
            \\\ help me help AIDS victims -- http://ICCF-Holland.org ///

            --~--~---------~--~----~------------~-------~--~----~
            You received this message from the "vim_use" maillist.
            For more information, visit http://www.vim.org/maillist.php
            -~----------~----~----~----~------~----~------~--~---
          • Andy Wokula
            ... The following code does almost the same as your naively implemented example : onoremap F : call FunctionName() function! FunctionName() normal!
            Message 5 of 26 , Oct 31, 2007
            • 0 Attachment
              Ben Schmidt schrieb:
              >> Well, I can see that you get the information, but this is not really a
              >> useful real-world example. Think of a user that wants to get something
              >> done for which v:operator is needed. And for which there is no other
              >> solution.
              >
              > Here's a somewhat naively implemented example where a custom text-object is
              > defined that allows you to operate on a function name whether the cursor is on the
              > name itself or on its arguments. You can yank with yF, change with cF, uppercase
              > with gUF, etc. I can't think of any other way to do this, or more complicated
              > language-based custom text-object definition--e.g. yank/change a whole conjunction
              > or disjunction in a logic language, yank or change the condition of an 'if' or
              > 'while' loop from anywhere within its body. Some of these would be more useful
              > than others, of course, but there are a lot of real world possibilities, I think.
              >
              > Ben.
              >
              > :onoremap F <Esc>:call OperateFunctionName()<CR>
              > function! OperateFunctionName()
              > let last_count = v:count
              > let last_op = v:operator
              > let last_reg = v:register
              > exe "normal \<Esc>"
              > while search('\(\%#\i\|\i\s*\%#\)\i*\s*(','ce',line('.')+1) == 0
              > normal [(
              > endwhile
              > exe "normal \<BS>\"_yiw"
              > echo 'normal '.(last_count>0?(last_count):'').'"'.last_reg.last_op.'e'
              > endfun

              The following code does almost the same as your "naively implemented example":

              onoremap F :<c-u>call FunctionName()<CR>

              function! FunctionName()
              normal! 0f(hviw
              endfunc

              It's already possible to move the cursor anywhere in the text, and
              using visual mode you can define a custom text object far away from
              the current cursor position.

              So I think your example doesn't hit, especially there is no need to
              know the operator.

              --
              Andy

              --~--~---------~--~----~------------~-------~--~----~
              You received this message from the "vim_use" maillist.
              For more information, visit http://www.vim.org/maillist.php
              -~----------~----~----~----~------~----~------~--~---
            • Ben Schmidt
              ... Could you explain to me why on earth this works?! I see that it does... Shouldn t the normal 0 complete the operation as it is a motion command?! Or the f
              Message 6 of 26 , Nov 1, 2007
              • 0 Attachment
                > The following code does almost the same as your "naively implemented example":
                >
                > onoremap F :<c-u>call FunctionName()<CR>
                >
                > function! FunctionName()
                > normal! 0f(hviw
                > endfunc

                Could you explain to me why on earth this works?! I see that it does...

                Shouldn't the normal 0 complete the operation as it is a motion command?! Or the f
                or the h...and then somehow visual mode is special and highlighting something with
                it magically makes it apply to the operator?

                Maybe there's something I don't know about in the documentation for omaps? I can't
                spot anything.

                That said, I still think using v:operator is quite possibly easier/more intuitive
                in this situation.

                Do you have a magic formula that solves the problem of accessing a register etc.
                in an omap which was the main reason this was being investigated?

                I'm still in awe of the fact that this works...

                Smiles,

                Ben.




                Send instant messages to your online friends http://au.messenger.yahoo.com


                --~--~---------~--~----~------------~-------~--~----~
                You received this message from the "vim_use" maillist.
                For more information, visit http://www.vim.org/maillist.php
                -~----------~----~----~----~------~----~------~--~---
              • Andy Wokula
                ... explains why ... also works (doesn t explain the Visual mode part though). ... Calls a function, but not a user function. Still haven t found a note about
                Message 7 of 26 , Nov 2, 2007
                • 0 Attachment
                  Ben Schmidt schrieb:
                  >> The following code does almost the same as your "naively implemented example":
                  >>
                  >> onoremap F :<c-u>call FunctionName()<CR>
                  >>
                  >> function! FunctionName()
                  >> normal! 0f(hviw
                  >> endfunc
                  >
                  > Could you explain to me why on earth this works?! I see that it does...
                  >
                  > Shouldn't the normal 0 complete the operation as it is a motion command?! Or the f
                  > or the h...and then somehow visual mode is special and highlighting something with
                  > it magically makes it apply to the operator?
                  >
                  > Maybe there's something I don't know about in the documentation for omaps? I can't
                  > spot anything.

                  Hmm right, not easy to find help pointers. Some I found:

                  :h {motion}

                  | - Ex commands can be used to move the cursor. This can be used to call a
                  | function that does some complicated motion. [...]

                  explains why
                  :onoremap F :normal! 0f(hviw<cr>
                  also works (doesn't explain the Visual mode part though).


                  :h operator

                  | *operator*
                  | [...]
                  | *exclusive-linewise*
                  | [...]
                  | You can use a ":" command for a motion. For example "d:call FindEnd()".
                  | But this can't be redone with "." if the command is more than one line.
                  | This can be repeated: >
                  | d:call search("f")<CR>
                  | This cannot be repeated: >
                  | d:if 1<CR>
                  | call search("f")<CR>
                  | endif<CR>

                  Calls a function, but not a user function.

                  Still haven't found a note about what happens when Visual mode is activated
                  while in Operator pending mode. Maybe because applying the operator on the
                  selection is the most natural thing to do then.

                  I'd appreciate a note just to know it's considered by Vim.

                  In the tips:
                  vimtip #1269: Indent text object

                  Actually there is only one thing to keep in mind: Executing the operator is
                  delayed until the function returns resp. Ex command finishes.

                  This allows for custom motions and custom text objects (via Visual mode).


                  > That said, I still think using v:operator is quite possibly easier/more intuitive
                  > in this situation.

                  IMHO it should be avoided, because it weakens the "orthogonality" of
                  operators and motions.

                  > Do you have a magic formula that solves the problem of accessing a register etc.
                  > in an omap which was the main reason this was being investigated?

                  I got ideas, but they don't work ...

                  --
                  Andy

                  --~--~---------~--~----~------------~-------~--~----~
                  You received this message from the "vim_use" maillist.
                  For more information, visit http://www.vim.org/maillist.php
                  -~----------~----~----~----~------~----~------~--~---
                • Andy Wokula
                  For Yankring plugin For Operator pending mode, we want to provide motions and text objects with a side effect, i.e. save the text that the operator is
                  Message 8 of 26 , Nov 2, 2007
                  • 0 Attachment
                    For Yankring plugin

                    " For Operator pending mode, we want to provide motions and text objects
                    " with a side effect, i.e. save the text that the operator is going to work
                    " on.

                    I think I've come close to sth that could be the solution ...
                    without v:operator

                    I observed that it is possible to yank without breaking operator pending
                    mode.

                    " exlusive motion examples:
                    " b, }, {
                    ono b :<c-u>call MyOmapBackw("b","")<cr>
                    ono } :<c-u>call MyOmapForw("}","")<cr>
                    ono { :<c-u>call MyOmapBackw("{","")<cr>

                    " inclusive motion examples:
                    " $
                    ono $ v:<c-u>call MyOmapForw("$","v")<cr>
                    ono v$ :<c-u>call MyOmapForw("$","v")<cr>

                    " text objects:
                    " TODO

                    " for setting the '[,'] markers, we need to distinguish the direction of the
                    " motion, forward or backward;
                    " use parameters [ ] or 2 different functions [X] <- bad idea if direction
                    " is unclear

                    func! MyOmapForw(motion, incl)
                    " incl - durchreichen zu SideEffect()
                    let l:count = v:count ? v:count : ""
                    normal! m[
                    exe "normal!" l:count.a:motion
                    normal! m]
                    call SideEffect(a:incl)
                    normal! `]
                    endfunc

                    func! MyOmapBackw(motion, incl)
                    " incl - durchreichen zu SideEffect()
                    let l:count = v:count ? v:count : ""
                    normal! m]
                    exe "normal!" l:count.a:motion
                    normal! m[
                    call SideEffect(a:incl)
                    normal! `[
                    endfunc

                    func! SideEffect(incl)
                    " catch into register r what the motion/text object covers
                    " args: `[, `]
                    let sav_rr = @r
                    " yanking is possible:
                    exe 'normal! `["ry'.a:incl.'`]'

                    " CUSTOM ACTION:
                    echo '"'.@r.'"'
                    sleep 1

                    let @r = sav_rr
                    endfunc

                    --
                    Andy


                    --~--~---------~--~----~------------~-------~--~----~
                    You received this message from the "vim_use" maillist.
                    For more information, visit http://www.vim.org/maillist.php
                    -~----------~----~----~----~------~----~------~--~---
                  • Andy Wokula
                    ... btw: minor bugfix ---^ This approach requires remapping of all the standard motions. Problem: It is unreliable, because in many cases the Operator pending
                    Message 9 of 26 , Nov 3, 2007
                    • 0 Attachment
                      Andy Wokula schrieb:
                      > For Yankring plugin
                      >
                      > " For Operator pending mode, we want to provide motions and text objects
                      > " with a side effect, i.e. save the text that the operator is going to work
                      > " on.
                      >
                      > I think I've come close to sth that could be the solution ...
                      > without v:operator
                      >
                      > I observed that it is possible to yank without breaking operator pending
                      > mode.
                      >
                      > " exlusive motion examples:
                      > " b, }, {
                      > ono b :<c-u>call MyOmapBackw("b","")<cr>
                      > ono } :<c-u>call MyOmapForw("}","")<cr>
                      > ono { :<c-u>call MyOmapBackw("{","")<cr>
                      >
                      > " inclusive motion examples:
                      > " $
                      > ono $ v:<c-u>call MyOmapForw("$","v")<cr>
                      > ono v$ :<c-u>call MyOmapForw("$","")<cr>
                      btw: minor bugfix ---^


                      This approach requires remapping of all the standard motions.

                      Problem: It is unreliable, because in many cases the Operator pending
                      mode variant behaves differently :-( , in the case of "cw" even
                      depending on the operator.

                      Examples:
                      "cw" is like "ce",
                      "dw" at the last word in the line doesn't join lines
                      (behaves like "de")
                      "dW" dito
                      "dl" at the last char in the line deletes the char, although the
                      (exclusive) "l" motion is not possible from there

                      These are just a few I stumbled over (how many others exist??).

                      I read
                      :h exclusive
                      :h exclusive-linewise
                      and noticed that the rules are also applied on my custom motions (so far
                      so good), but in case of "dw" the two rules don't help, they are even
                      contradicting (Example:
                      WordOnLine1
                      WordOnLine2
                      with cursor on WordOnLine1, "d:normal w<Enter>" deletes the whole line
                      (Exception 2 applies)).

                      I'm quite disappointed about all the subtle exceptions ...
                      David, currently I think v:operator will be more useful and reliable.

                      --
                      Andy

                      --~--~---------~--~----~------------~-------~--~----~
                      You received this message from the "vim_use" maillist.
                      For more information, visit http://www.vim.org/maillist.php
                      -~----------~----~----~----~------~----~------~--~---
                    • Ben Schmidt
                      OK, folks, After reading feedback, etc., here is a revised patch. It s just the documentation that is different from the previous patch. In the end, given that
                      Message 10 of 26 , Nov 4, 2007
                      • 0 Attachment
                        OK, folks,

                        After reading feedback, etc., here is a revised patch. It's just the documentation
                        that is different from the previous patch.

                        In the end, given that a number of things can be done without v:operator, as Andy
                        demonstrated, and that Yankring is a pretty specific example, I thought perhaps
                        the best thing would be to put a brief example analogous to the v:prevcount
                        example which is right nextdoor in the docs.

                        If you still think a lengthier example is better, though, Bram, I'm happy to
                        revise the patch again. I thought this, or a scaled-down count-ignorant version
                        might be a more useful lengthy example (compared to the function name thing I
                        suggested before):

                        :" Defines a motion/text-object <C> which allows you to operate on
                        :" the {count}th column of a tab-delimited table, or the column
                        :" the cursor is currently in if no count is given.
                        :onoremap C <Esc>:call OperateColumn()<CR>
                        :function! OperateColumn()
                        : let c = v:prevcount
                        : if c == 0
                        : call search('^\|\t\zs','bc',line("."))
                        : else
                        : call cursor(line("."),1)
                        : while search('\v(\zs[^\t]*(\t|$)){'.c.'}','c',line(".")) == 0
                        : call setline(line("."),getline(line("."))."\t")
                        : endwhile
                        : endif
                        : call feedkeys('"'.v:register.v:operator)
                        : if strpart(getline(line('.')),col('.')-1,1) == "\t"
                        : call feedkeys(":\<CR>")
                        : else
                        : call feedkeys(search('\t','n',line(".")) == 0 ? "$" : "t\t")
                        : endif
                        :endfun

                        Ben.




                        --~--~---------~--~----~------------~-------~--~----~
                        You received this message from the "vim_use" maillist.
                        For more information, visit http://www.vim.org/maillist.php
                        -~----------~----~----~----~------~----~------~--~---
                      • Ben Schmidt
                        ... I don t think this is an issue, because (1) nobody can expect to know {motion} before it has happened! and (2) there is sufficient information available
                        Message 11 of 26 , Nov 4, 2007
                        • 0 Attachment
                          > I believe there is a relating 'inverse' problem here :
                          > If you are going to use 'operatorfunc', you are not able
                          > to tell what kind of motion you are going to operate on
                          > and, more generally,whether it will be an inclusive or
                          > exclusive one.

                          I don't think this is an issue, because (1) nobody can expect to know {motion}
                          before it has happened! and (2) there is sufficient information available when
                          operatorfunc is called to deduce all you need to know: the '[ and '] marks,
                          whether it's line-, character- or block-wise motion as a function argument, and
                          the current cursor position.

                          Ben.




                          Send instant messages to your online friends http://au.messenger.yahoo.com


                          --~--~---------~--~----~------------~-------~--~----~
                          You received this message from the "vim_use" maillist.
                          For more information, visit http://www.vim.org/maillist.php
                          -~----------~----~----~----~------~----~------~--~---
                        • Ben Schmidt
                          [CCing vim_dev; apologies for my continued disorganised postings!] OK, folks, After reading feedback, etc., here is a revised patch. It s just the
                          Message 12 of 26 , Nov 4, 2007
                          • 0 Attachment
                            [CCing vim_dev; apologies for my continued disorganised postings!]

                            OK, folks,

                            After reading feedback, etc., here is a revised patch. It's just the documentation
                            that is different from the previous patch.

                            In the end, given that a number of things can be done without v:operator, as Andy
                            demonstrated, and that Yankring is a pretty specific example, I thought perhaps
                            the best thing would be to put a brief example analogous to the v:prevcount
                            example which is right nextdoor in the docs.

                            If you still think a lengthier example is better, though, Bram, I'm happy to
                            revise the patch again. I thought this, or a scaled-down count-ignorant version
                            might be a more useful lengthy example (compared to the function name thing I
                            suggested before):

                            :" Defines a motion/text-object <C> which allows you to operate on
                            :" the {count}th column of a tab-delimited table, or the column
                            :" the cursor is currently in if no count is given.
                            :onoremap C <Esc>:call OperateColumn()<CR>
                            :function! OperateColumn()
                            : let c = v:prevcount
                            : if c == 0
                            : call search('^\|\t\zs','bc',line("."))
                            : else
                            : call cursor(line("."),1)
                            : while search('\v(\zs[^\t]*(\t|$)){'.c.'}','c',line(".")) == 0
                            : call setline(line("."),getline(line("."))."\t")
                            : endwhile
                            : endif
                            : call feedkeys('"'.v:register.v:operator)
                            : if strpart(getline(line('.')),col('.')-1,1) == "\t"
                            : call feedkeys(":\<CR>")
                            : else
                            : call feedkeys(search('\t','n',line(".")) == 0 ? "$" : "t\t")
                            : endif
                            :endfun

                            Ben.







                            --~--~---------~--~----~------------~-------~--~----~
                            You received this message from the "vim_use" maillist.
                            For more information, visit http://www.vim.org/maillist.php
                            -~----------~----~----~----~------~----~------~--~---
                          Your message has been successfully submitted and would be delivered to recipients shortly.