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

Re: invoking mappings via normal broken

Expand Messages
  • F. G. Marx
    ... After some investigation, it emerges that the new constaints on normal prohibit using it to obtain any *input* at all. The normal call must complete and
    Message 1 of 10 , Dec 31, 1969
      On Fri, 20 Apr 2001 11:11:48 +0200, Bram Moolenaar <Bram@...> wrote:
      >
      >> I have several mappings which end in ^D, e.g.:
      >>
      >> map _m :e ~/.vim/^D
      >>
      >> which enables a list of the files in the directory,
      >> and then further allows completion of the filenames displayed.
      >>
      >> I then call some of these via normal, e.g.:
      >>
      >> normal _m
      >>
      >> This broke with cvs upgrade from 6.0z to 6.0ab.
      >>
      >> Invoking _m as a *regular* mapping still lists and completes properly.
      >
      >Using an unfinished command with ":normal" was never a good idea. In the new
      >version it is no longer possible, because the command will see Esc typed,
      >which cancels the command. There is a technical reason for this.
      >
      >Why do you use "normal _m"?
      >


      After some investigation, it emerges that the new constaints on normal
      prohibit using it to obtain any *input* at all. The normal call must
      complete and return, operating on the buffer, in effect only *output*,
      no longer able to accept and process command-line input.


      That's of course what I'm doing with it, as follows:
      1. map _m to a function;
      2. prepare a question for the user, depending on context,
      in the function:
      A. prepend `:SomeCommand'
      B. append `^D'
      C. thereby enabling command-line completion (:SomeCommand)
      with possibilities pre-listed (the ^D)
      3. calling: execute 'normal ' . prepend . context . '/^D'

      Here is the actual function:
      ----------------------------
      au BufEnter VMailSubjects map <buffer> o :call VMailSaveMail('o')<cr>
      au BufEnter VMailSubjects map <buffer> O :call VMailSaveMail('O')<cr>
      au BufEnter VMailSubjects map <buffer> s :call VMailSaveMail('s')<cr>


      command! -nargs=? -complete=file VMailSave :call VMailAppendMail(<f-args>)


      " this function enables three modes of message save:
      " 1. save unconditionally to last saved file: `o'
      " 2. prompt with name of directory of last saved file: `O'
      " 3. prompt with default mail save directory: `s' (or not previous save)
      "
      function! VMailSaveMail(which)
      if exists('g:vmail_last_saved')
      if (a:which == 'o')
      silent call VMailAppendMail(g:vmail_last_saved)
      return
      elseif (a:which == 'O')
      exe 'normal :VMailSave ' . fnamemodify(g:vmail_last_saved, ":h")
      return
      endif
      endif
      exe 'normal :VMailSave ' . g:vmail_savedir . '/'
      endf
      ----------------------------


      This has worked perfectly.


      To my mind, the old semantic of `normal' is the correct one: ... but I
      can't quite formulate what that was ;-) Access to the internal state of
      vim from a function? Access to the typeahead buffer? Ability to be the
      user either as the user or through `normal' ;-?


      If `normal' must be curtailed in order to function correctly in
      event-handling, will anyone ever have a need for the kind of
      command-line manipulations and processing I'm showing here, and might
      we, if they do, add it back in somehow?


      Thanks,


      /f
      ------------------------------------------------
      f.g.marx <fmarx@...>
    • Bram Moolenaar
      ... That s right. The argument of :normal must be a complete command, it won t wait for the user to type anything. ... You could do something similar
      Message 2 of 10 , Apr 28, 2001
        f.g. Marx wrote:

        > After some investigation, it emerges that the new constaints on normal
        > prohibit using it to obtain any *input* at all. The normal call must
        > complete and return, operating on the buffer, in effect only *output*,
        > no longer able to accept and process command-line input.

        That's right. The argument of ":normal" must be a complete command, it won't
        wait for the user to type anything.

        > That's of course what I'm doing with it, as follows:
        > 1. map _m to a function;
        > 2. prepare a question for the user, depending on context,
        > in the function:
        > A. prepend `:SomeCommand'
        > B. append `^D'
        > C. thereby enabling command-line completion (:SomeCommand)
        > with possibilities pre-listed (the ^D)
        > 3. calling: execute 'normal ' . prepend . context . '/^D'

        You could do something similar without ":normal":

        map _m to ":call VMailSaveMail()<CR>_x"
        in VMailSaveMail() map _x to what you want to do

        Didn't try this, but I would expect this to work. The trick is to remap _x on
        the fly.

        > To my mind, the old semantic of `normal' is the correct one: ... but I
        > can't quite formulate what that was ;-) Access to the internal state of
        > vim from a function? Access to the typeahead buffer? Ability to be the
        > user either as the user or through `normal' ;-?

        The old way ":normal" worked was a bit messy. That's why I changed it. Not
        only does this allow using ":normal" in an event handler, it should also avoid
        potential bugs.

        --
        I used to wonder about the meaning of life. But I looked it
        up in the dictionary under "L" and there it was - the meaning
        of life. It was less than I expected. - Dogbert

        /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
        ((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim )))
        \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///
      • Benji Fisher
        ... [snip] I do not think that works. I tried ... When I executed the map, I got input _x on the command line, which does not have the desired effect.
        Message 3 of 10 , Apr 28, 2001
          Bram Moolenaar wrote:

          > f.g. Marx wrote:
          >
          >
          >> After some investigation, it emerges that the new constaints on normal
          >> prohibit using it to obtain any *input* at all. The normal call must
          >> complete and return, operating on the buffer, in effect only *output*,
          >> no longer able to accept and process command-line input.
          >
          >
          > That's right. The argument of ":normal" must be a complete command, it won't
          > wait for the user to type anything.
          >
          >
          >> That's of course what I'm doing with it, as follows:
          >> 1. map _m to a function;
          >> 2. prepare a question for the user, depending on context,
          >> in the function:
          >> A. prepend `:SomeCommand'
          >> B. append `^D'
          >> C. thereby enabling command-line completion (:SomeCommand)
          >> with possibilities pre-listed (the ^D)
          >> 3. calling: execute 'normal ' . prepend . context . '/^D'
          >
          >
          > You could do something similar without ":normal":
          >
          > map _m to ":call VMailSaveMail()<CR>_x"
          > in VMailSaveMail() map _x to what you want to do
          >
          > Didn't try this, but I would expect this to work. The trick is to remap _x on
          > the fly.
          [snip]

          I do not think that works. I tried

          :map _m :call Foo()<CR>_x
          :fun Foo()
          : let bar = input("input: ")
          : execute "map _x :e " . bar
          : endfun

          When I executed the map, I got

          input _x

          on the command line, which does not have the desired effect.

          --Benji Fisher
        • Bram Moolenaar
          ... The idea was that the function sets up the mapping, depending of the context. No, you can t ask the user to type something, it will eat the characters from
          Message 4 of 10 , Apr 29, 2001
            Benji Fisher wrote:

            > I do not think that works. I tried
            >
            > :map _m :call Foo()<CR>_x
            > :fun Foo()
            > : let bar = input("input: ")
            > : execute "map _x :e " . bar
            > : endfun
            >
            > When I executed the map, I got
            >
            > input _x
            >
            > on the command line, which does not have the desired effect.

            The idea was that the function sets up the mapping, depending of the context.
            No, you can't ask the user to type something, it will eat the characters from
            the mapping. The ":normal" command also couldn't do that.

            This works for me:

            :map _m :call Foo()<CR>_x
            :fun Foo()
            : exe "map _x " . g:l
            :endfun

            Try it out:
            :let l = "a111"
            _m
            <Esc>
            :let l = "a22"
            _m

            Note that you can be left in Insert mode this way, which wasn't possible with
            ":normal".

            --
            LARGE MAN: Who's that then?
            CART DRIVER: (Grudgingly) I dunno, Must be a king.
            LARGE MAN: Why?
            CART DRIVER: He hasn't got shit all over him.
            "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

            /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
            ((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim )))
            \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///
          • Benji Fisher
            Bram Moolenaar wrote: [snip] ... Yes, but the original question was how to get a mapping that got information from the user (hence my example with input()) and
            Message 5 of 10 , Apr 29, 2001
              Bram Moolenaar wrote:

              [snip]

              >
              > The idea was that the function sets up the mapping, depending of the context.
              > No, you can't ask the user to type something, it will eat the characters from
              > the mapping. The ":normal" command also couldn't do that.
              >
              > This works for me:
              >
              > :map _m :call Foo()<CR>_x
              > :fun Foo()
              > : exe "map _x " . g:l
              > :endfun

              Yes, but the original question was how to get a mapping that got
              information from the user (hence my example with input()) and then did
              :e <some stuff><C-D>
              The old behavior of :normal allowed this:
              :execute "normal :e" <some stuff> "\<C-D>"
              I cannot think of how to get this effect with the new restriction that
              :normal be given a "complete command."

              Maybe the original poster can make do with
              :execute "bro e" <some stuff>

              --Benji Fisher
            • Bram Moolenaar
              ... No, there was no input from the user. That would have been impossible, because the following CTRL-D would have been eaten. ... The restriction for using a
              Message 6 of 10 , Apr 29, 2001
                Benji Fisher wrote:

                > > The idea was that the function sets up the mapping, depending of the
                > > context. No, you can't ask the user to type something, it will eat the
                > > characters from the mapping. The ":normal" command also couldn't do that.
                > >
                > > This works for me:
                > >
                > > :map _m :call Foo()<CR>_x
                > > :fun Foo()
                > > : exe "map _x " . g:l
                > > :endfun
                >
                > Yes, but the original question was how to get a mapping that got
                > information from the user (hence my example with input()) and then did
                > :e <some stuff><C-D>

                No, there was no input from the user. That would have been impossible,
                because the following CTRL-D would have been eaten.

                > The old behavior of :normal allowed this:
                > :execute "normal :e" <some stuff> "\<C-D>"
                > I cannot think of how to get this effect with the new restriction that
                > :normal be given a "complete command."

                The restriction for using a complete command already existed. However, before
                you could get away with doing half a command, because there was no check for
                it.

                --
                ARTHUR: What are you going to do. bleed on me?
                "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

                /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                ((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim )))
                \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///
              • F. G. Marx
                What I need is completion (path, filename, preferably everything) when interacting with user. I used to rig up ``normal to do this. But I think the same
                Message 7 of 10 , Apr 30, 2001
                  What I need is completion (path, filename, preferably everything)
                  when interacting with user. I used to rig up ``normal'' to do this.
                  But I think the same thing could be accomplished via extending
                  ``input''. Can we just have f_input call ex_getline?


                  The semantics of ``normal'' are radically altered with this change. But
                  normal is obviously not in vi, so.... The change permits normal to be
                  called from autocommands, where it was prohibited, and prohibits gaining
                  command line input, which was permitted.


                  On Sun, 29 Apr 2001 20:58:41 +0200, Bram Moolenaar <Bram@...> wrote:
                  >
                  >
                  >
                  >Benji Fisher wrote:
                  >
                  >> > The idea was that the function sets up the mapping, depending of the
                  >> > context. No, you can't ask the user to type something, it will eat the
                  >> > characters from the mapping. The ":normal" command also couldn't do that.
                  >> >
                  >> > This works for me:
                  >> >
                  >> > :map _m :call Foo()<CR>_x
                  >> > :fun Foo()
                  >> > : exe "map _x " . g:l
                  >> > :endfun
                  >>
                  >> Yes, but the original question was how to get a mapping that got
                  >> information from the user (hence my example with input()) and then did
                  >> :e <some stuff><C-D>
                  >
                  >No, there was no input from the user. That would have been impossible,
                  >because the following CTRL-D would have been eaten.
                  >
                  >> The old behavior of :normal allowed this:
                  >> :execute "normal :e" <some stuff> "\<C-D>"
                  >> I cannot think of how to get this effect with the new restriction that
                  >> :normal be given a "complete command."
                  >
                  >The restriction for using a complete command already existed. However, before
                  >you could get away with doing half a command, because there was no check for
                  >it.
                  >
                  >--
                  >ARTHUR: What are you going to do. bleed on me?
                  > "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
                  >
                  > /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                  >((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim )))
                  > \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///
                  >
                  >
                  ------------------------------------------------
                  f.g.marx <fmarx@...>
                • Bram Moolenaar
                  ... input() does use ex_getline(), in a way. But it doesn t allow completion. If you want completion, you could perhaps define a User command. Using input()
                  Message 8 of 10 , Apr 30, 2001
                    f.g.Marx wrote:

                    > What I need is completion (path, filename, preferably everything)
                    > when interacting with user. I used to rig up ``normal'' to do this.
                    > But I think the same thing could be accomplished via extending
                    > ``input''. Can we just have f_input call ex_getline?

                    input() does use ex_getline(), in a way. But it doesn't allow completion.
                    If you want completion, you could perhaps define a User command. Using
                    input() to obtain a ":" command line sounds a bit strange to me...

                    > The semantics of ``normal'' are radically altered with this change. But
                    > normal is obviously not in vi, so.... The change permits normal to be
                    > called from autocommands, where it was prohibited, and prohibits gaining
                    > command line input, which was permitted.

                    The official semantics of ":normal" didn't change. I still have to see an
                    example that worked in previous versions and used ":normal" as it was
                    intended. I would otherwise try to keep undocumented features, but in this
                    case the change is needed to fix something else.

                    Your case was a bit special, since you used a ":" command that wasn't
                    complete. The stuff that waits for the command line isn't optimized to skip
                    redrawing when there is typeahead, and thus it happened to work for you. If I
                    would have implemented an optimization not to redraw when the characters were
                    not typed, like it's done in the main loop and for Insert mode, you would not
                    have seen the characters from ":normal". It accidentally worked...

                    --
                    Contrary to popular belief, it's often your clothing that gets promoted, not
                    you.
                    (Scott Adams - The Dilbert principle)

                    /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                    ((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim )))
                    \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///
                  • F. G. Marx
                    Right, I m beginning to see the point - a complete command means no possibility of user input, and that s been there, implicitly, from the beginning. O.k., so
                    Message 9 of 10 , Apr 30, 2001
                      Right, I'm beginning to see the point - a complete command means no
                      possibility of user input, and that's been there, implicitly, from the
                      beginning.


                      O.k., so I've turned my attention to trying to recast what I'm doing in
                      User commands. The function I wrote about the other day, if mapped
                      straight to a user command, and not to a normal call, is working.
                      But this is not:


                      function! ENotesNotes(...)
                      if exists('a:1')
                      exe 'split ' . a:1
                      $
                      startinsert!
                      endif
                      endf
                      command! -nargs=? -complete=file ENotes :call ENotesNotes(<f-args>)


                      function! EN()
                      if exists("notes_buffer")
                      exe "buffer " notes_buffer
                      $
                      startinsert!
                      else
                      "map _enotes :e /usr/share/doc/local/Notes/
                      "normal _enotes
                      ENotes /usr/share/doc/local/Notes/^D
                      endif
                      endf


                      The difference is: I call the user command from
                      a) a call to User-command in a mapping (works),
                      b) a call to User-command in a function (doesn't work).


                      Thanks for working with me on this,


                      /f


                      Bram Moolenaar writes:
                      >
                      > f.g.Marx wrote:
                      >
                      > > What I need is completion (path, filename, preferably everything)
                      > > when interacting with user. I used to rig up ``normal'' to do this.
                      > > But I think the same thing could be accomplished via extending
                      > > ``input''. Can we just have f_input call ex_getline?
                      >
                      > input() does use ex_getline(), in a way. But it doesn't allow completion.
                      > If you want completion, you could perhaps define a User command. Using
                      > input() to obtain a ":" command line sounds a bit strange to me...
                      >
                      > > The semantics of ``normal'' are radically altered with this change. But
                      > > normal is obviously not in vi, so.... The change permits normal to be
                      > > called from autocommands, where it was prohibited, and prohibits gaining
                      > > command line input, which was permitted.
                      >
                      > The official semantics of ":normal" didn't change. I still have to see an
                      > example that worked in previous versions and used ":normal" as it was
                      > intended. I would otherwise try to keep undocumented features, but in this
                      > case the change is needed to fix something else.
                      >
                      > Your case was a bit special, since you used a ":" command that wasn't
                      > complete. The stuff that waits for the command line isn't optimized to skip
                      > redrawing when there is typeahead, and thus it happened to work for you. If I
                      > would have implemented an optimization not to redraw when the characters were
                      > not typed, like it's done in the main loop and for Insert mode, you would not
                      > have seen the characters from ":normal". It accidentally worked...
                      ------------------------------------------------
                      f.g.marx <fmarx@...>
                    • Bram Moolenaar
                      ... Right. ... [...] ... That doesn t work, because it s executed as it is, not as if it was typed. Since you want that CTRL-D to be handled like it was typed,
                      Message 10 of 10 , May 1, 2001
                        f.g.marx wrote:

                        > Right, I'm beginning to see the point - a complete command means no
                        > possibility of user input, and that's been there, implicitly, from the
                        > beginning.

                        Right.

                        > O.k., so I've turned my attention to trying to recast what I'm doing in
                        > User commands. The function I wrote about the other day, if mapped
                        > straight to a user command, and not to a normal call, is working.
                        > But this is not:
                        [...]
                        > ENotes /usr/share/doc/local/Notes/^D

                        That doesn't work, because it's executed as it is, not as if it was typed.
                        Since you want that CTRL-D to be handled like it was typed, you must use a
                        mapping.

                        I assume you call the EN() function from a mapping, e.g.:

                        map <F2> :call EN()<CR>

                        Since the EN() function can't pretend characters to be typed by the user, this
                        has to be included in the mapping. The EN() function can be used to set what
                        is to happen:

                        map <F2> :call EN()<CR>,x

                        fun EN()
                        if a
                        do-something
                        map ,x i " start insertion
                        else
                        do-something-else
                        map ,x :e /usr/share/doc/local/Notes/^D
                        endif
                        endfun

                        Hope you get the idea.

                        --
                        hundred-and-one symptoms of being an internet addict:
                        1. You actually wore a blue ribbon to protest the Communications Decency Act.

                        /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                        ((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim )))
                        \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///
                      Your message has been successfully submitted and would be delivered to recipients shortly.